selective generation of settings for GPG + isolated gpg homedir

This commit is contained in:
Jared Petersen 2020-05-12 01:11:43 -07:00
parent 5e3159d960
commit 8bc07f9980
7 changed files with 30386 additions and 95 deletions

View file

@ -66,7 +66,21 @@ describe('auth tests', () => {
await io.rmRF(altHome); await io.rmRF(altHome);
}, 100000); }, 100000);
it('creates settings.xml with all data', async () => { it('creates settings.xml with minimal configuration', async () => {
const id = 'packages';
const username = 'UNAME';
const password = 'TOKEN';
await auth.configAuthentication(id, username, password);
expect(fs.existsSync(m2Dir)).toBe(true);
expect(fs.existsSync(settingsFile)).toBe(true);
expect(fs.readFileSync(settingsFile, 'utf-8')).toEqual(
auth.generate(id, username, password)
);
}, 100000);
it('creates settings.xml with gpg data', async () => {
const id = 'packages'; const id = 'packages';
const username = 'UNAME'; const username = 'UNAME';
const password = 'TOKEN'; const password = 'TOKEN';
@ -145,27 +159,41 @@ describe('auth tests', () => {
); );
}, 100000); }, 100000);
it('escapes invalid XML inputs', () => { it('generates valid settings.xml', () => {
const id = 'packages'; const id = 'packages';
const username = 'USER'; const username = 'USER';
const password = '&<>"\'\'"><&'; const password = '&<>"\'\'"><&';
const gpgPassphrase = 'PASSPHRASE'; const gpgPassphrase = 'PASSPHRASE';
expect(auth.generate(id, username, password, gpgPassphrase)).toEqual(` const expectedSettings = `<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
<settings> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<servers> xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
<server> <servers>
<id>${id}</id> <server>
<username>\${env.${username}}</username> <id>${id}</id>
<password>\${env.&amp;&lt;&gt;&quot;&apos;&apos;&quot;&gt;&lt;&amp;}</password> <username>\${env.${username}}</username>
</server> <password>\${env.&amp;&lt;&gt;"''"&gt;&lt;&amp;}</password>
<server> </server>
<id>gpg.passphrase</id> <server>
<passphrase>\${env.${gpgPassphrase}}</passphrase> <id>gpg.passphrase</id>
</server> <passphrase>\${env.${gpgPassphrase}}</passphrase>
</servers> </server>
</settings> </servers>
`); <profiles>
<profile>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<gpg.homedir>${tempDir}</gpg.homedir>
</properties>
</profile>
</profiles>
</settings>`;
expect(auth.generate(id, username, password, gpgPassphrase)).toEqual(
expectedSettings
);
}); });
it('imports gpg private key', async () => { it('imports gpg private key', async () => {

View file

@ -10,7 +10,7 @@ describe('util tests', () => {
describe('getTempDir', () => { describe('getTempDir', () => {
it('gets temp dir using env', () => { it('gets temp dir using env', () => {
process.env['RUNNER_TEMP'] = 'defaulttmp' process.env['RUNNER_TEMP'] = 'defaulttmp';
const util = require('../src/util'); const util = require('../src/util');
const tempDir = util.getTempDir(); const tempDir = util.getTempDir();
@ -25,7 +25,9 @@ describe('util tests', () => {
const tempDir = util.getTempDir(); const tempDir = util.getTempDir();
expect(tempDir).toEqual(path.join(process.env['USERPROFILE'], 'actions', 'temp')); expect(tempDir).toEqual(
path.join(process.env['USERPROFILE'], 'actions', 'temp')
);
}); });
it('gets temp dir for windows using c drive', () => { it('gets temp dir for windows using c drive', () => {

30248
dist/index.js generated vendored

File diff suppressed because it is too large Load diff

78
package-lock.json generated
View file

@ -430,6 +430,74 @@
"@types/yargs": "^13.0.0" "@types/yargs": "^13.0.0"
} }
}, },
"@oozcitak/dom": {
"version": "1.15.5",
"resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-1.15.5.tgz",
"integrity": "sha512-L6v3Mwb0TaYBYgeYlIeBaHnc+2ZEaDSbFiRm5KmqZQSoBlbPlf+l6aIH/sD5GUf2MYwULw00LT7+dOnEuAEC0A==",
"requires": {
"@oozcitak/infra": "1.0.5",
"@oozcitak/url": "1.0.0",
"@oozcitak/util": "8.0.0"
},
"dependencies": {
"@oozcitak/util": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-8.0.0.tgz",
"integrity": "sha512-+9Hq6yuoq/3TRV/n/xcpydGBq2qN2/DEDMqNTG7rm95K6ZE2/YY/sPyx62+1n8QsE9O26e5M1URlXsk+AnN9Jw=="
}
}
},
"@oozcitak/infra": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@oozcitak/infra/-/infra-1.0.5.tgz",
"integrity": "sha512-o+zZH7M6l5e3FaAWy3ojaPIVN5eusaYPrKm6MZQt0DKNdgXa2wDYExjpP0t/zx+GoQgQKzLu7cfD8rHCLt8JrQ==",
"requires": {
"@oozcitak/util": "8.0.0"
},
"dependencies": {
"@oozcitak/util": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-8.0.0.tgz",
"integrity": "sha512-+9Hq6yuoq/3TRV/n/xcpydGBq2qN2/DEDMqNTG7rm95K6ZE2/YY/sPyx62+1n8QsE9O26e5M1URlXsk+AnN9Jw=="
}
}
},
"@oozcitak/url": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@oozcitak/url/-/url-1.0.0.tgz",
"integrity": "sha512-LGrMeSxeLzsdaitxq3ZmBRVOrlRRQIgNNci6L0VRnOKlJFuRIkNm4B+BObXPCJA6JT5bEJtrrwjn30jueHJYZQ==",
"requires": {
"@oozcitak/infra": "1.0.3",
"@oozcitak/util": "1.0.2"
},
"dependencies": {
"@oozcitak/infra": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@oozcitak/infra/-/infra-1.0.3.tgz",
"integrity": "sha512-9O2wxXGnRzy76O1XUxESxDGsXT5kzETJPvYbreO4mv6bqe1+YSuux2cZTagjJ/T4UfEwFJz5ixanOqB0QgYAag==",
"requires": {
"@oozcitak/util": "1.0.1"
},
"dependencies": {
"@oozcitak/util": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-1.0.1.tgz",
"integrity": "sha512-dFwFqcKrQnJ2SapOmRD1nQWEZUtbtIy9Y6TyJquzsalWNJsKIPxmTI0KG6Ypyl8j7v89L2wixH9fQDNrF78hKg=="
}
}
},
"@oozcitak/util": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-1.0.2.tgz",
"integrity": "sha512-4n8B1cWlJleSOSba5gxsMcN4tO8KkkcvXhNWW+ADqvq9Xj+Lrl9uCa90GRpjekqQJyt84aUX015DG81LFpZYXA=="
}
}
},
"@oozcitak/util": {
"version": "8.3.3",
"resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-8.3.3.tgz",
"integrity": "sha512-Ufpab7G5PfnEhQyy5kDg9C8ltWJjsVT1P/IYqacjstaqydG4Q21HAT2HUZQYBrC/a1ZLKCz87pfydlDvv8y97w=="
},
"@types/babel__core": { "@types/babel__core": {
"version": "7.1.3", "version": "7.1.3",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz",
@ -4955,6 +5023,16 @@
"integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==",
"dev": true "dev": true
}, },
"xmlbuilder2": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-2.1.2.tgz",
"integrity": "sha512-PI710tmtVlQ5VmwzbRTuhmVhKnj9pM8Si+iOZCV2g2SNo3gCrpzR2Ka9wNzZtqfD+mnP+xkrqoNy0sjKZqP4Dg==",
"requires": {
"@oozcitak/dom": "1.15.5",
"@oozcitak/infra": "1.0.5",
"@oozcitak/util": "8.3.3"
}
},
"y18n": { "y18n": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",

View file

@ -29,7 +29,8 @@
"@actions/http-client": "^1.0.6", "@actions/http-client": "^1.0.6",
"@actions/io": "^1.0.0", "@actions/io": "^1.0.0",
"@actions/tool-cache": "^1.3.1", "@actions/tool-cache": "^1.3.1",
"semver": "^6.1.1" "semver": "^6.1.1",
"xmlbuilder2": "^2.1.2"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^24.0.13", "@types/jest": "^24.0.13",

View file

@ -5,6 +5,7 @@ import * as core from '@actions/core';
import * as io from '@actions/io'; import * as io from '@actions/io';
import * as exec from '@actions/exec'; import * as exec from '@actions/exec';
import * as util from './util'; import * as util from './util';
import {create as xmlCreate} from 'xmlbuilder2';
export const M2_DIR = '.m2'; export const M2_DIR = '.m2';
export const TEMP_DIR = util.getTempDir(); export const TEMP_DIR = util.getTempDir();
@ -39,10 +40,11 @@ export async function configAuthentication(
); );
await io.mkdirP(settingsDirectory); await io.mkdirP(settingsDirectory);
core.debug(`created directory ${settingsDirectory}`); core.debug(`created directory ${settingsDirectory}`);
const isGpgEnabled = gpgPrivateKey !== DEFAULT_GPG_PRIVATE_KEY;
await write( await write(
settingsDirectory, settingsDirectory,
SETTINGS_FILE, SETTINGS_FILE,
generate(id, username, password, gpgPassphrase) generate(id, username, password, isGpgEnabled ? gpgPassphrase : null)
); );
if (gpgPrivateKey !== DEFAULT_GPG_PRIVATE_KEY) { if (gpgPrivateKey !== DEFAULT_GPG_PRIVATE_KEY) {
@ -51,37 +53,53 @@ export async function configAuthentication(
} }
} }
function escapeXML(value: string) {
return value
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;');
}
// only exported for testing purposes // only exported for testing purposes
export function generate( export function generate(
id = DEFAULT_ID, id: string,
username = DEFAULT_USERNAME, username: string,
password = DEFAULT_PASSWORD, password: string,
gpgPassphrase = DEFAULT_GPG_PASSPHRASE gpgPassphrase: string | null = null
) { ) {
return ` const xmlObj: any = {
<settings> settings: {
<servers> '@xmlns': 'http://maven.apache.org/SETTINGS/1.0.0',
<server> '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
<id>${escapeXML(id)}</id> '@xsi:schemaLocation':
<username>\${env.${escapeXML(username)}}</username> 'http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd',
<password>\${env.${escapeXML(password)}}</password> servers: {
</server> server: [
<server> {
<id>gpg.passphrase</id> id: id,
<passphrase>\${env.${escapeXML(gpgPassphrase)}}</passphrase> username: `\${env.${username}}`,
</server> password: `\${env.${password}}`
</servers> }
</settings> ]
`; }
}
};
if (gpgPassphrase !== null) {
const gpgServer = {
id: 'gpg.passphrase',
passphrase: `\${env.${gpgPassphrase}}`
};
xmlObj.settings.servers.server.push(gpgServer);
xmlObj.settings.profiles = {
profile: [
{
activation: {
activeByDefault: true
},
properties: {
'gpg.homedir': TEMP_DIR
}
}
]
};
}
return xmlCreate(xmlObj).end({headless: true, prettyPrint: true, width: 80});
} }
async function write(directory: string, file: string, contents: string) { async function write(directory: string, file: string, contents: string) {

View file

@ -6,7 +6,9 @@ export function getTempDir() {
let baseLocation; let baseLocation;
if (isWindows()) { if (isWindows()) {
// On windows use the USERPROFILE env variable // On windows use the USERPROFILE env variable
baseLocation = (process.env['USERPROFILE']) ? process.env['USERPROFILE'] : 'C:\\'; baseLocation = process.env['USERPROFILE']
? process.env['USERPROFILE']
: 'C:\\';
} else { } else {
if (process.platform === 'darwin') { if (process.platform === 'darwin') {
baseLocation = '/Users'; baseLocation = '/Users';
@ -20,5 +22,5 @@ export function getTempDir() {
} }
export function isWindows() { export function isWindows() {
return (process.platform === 'win32'); return process.platform === 'win32';
} }