Skip to content

Commit 5aa178a

Browse files
authored
add test asserting private GHCR Features
1 parent 4967462 commit 5aa178a

2 files changed

Lines changed: 33 additions & 20 deletions

File tree

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
3+
"features": {
4+
"ghcr.io/devcontainers/private-feature-set-for-tests/color:1": {
5+
"favorite": "pink"
6+
}
7+
}
8+
}

src/test/container-features/registryCompatibilityOCI.test.ts

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const pkg = require('../../../package.json');
1111

1212
enum AuthStrategy {
1313
Anonymous,
14+
GitHubToken,
1415
DockerConfigAuthFile,
1516
// PlatformCredentialHelper,
1617
// RefreshToken,
@@ -24,11 +25,10 @@ interface TestPlan {
2425
testCommandResult?: RegExp;
2526
// Optionally tell the test to set up with a specfic auth strategy.
2627
// If not set, the test will run with anonymous.
27-
// NOTE:
28-
// These will be skipped unless the environment has the relevant 'authCredentialEnvSecret' set in the environment.
28+
// NOTE: These will be skipped unless the environment has the relevant 'authStrategyKey' set in the environment.
29+
// This data is specific to each strategy and parsed about below accordingly.
2930
useAuthStrategy?: AuthStrategy;
30-
// Format: registry|username|passwordOrToken
31-
authCredentialEnvSecret?: string;
31+
authStrategyKey?: string;
3232
}
3333

3434
const defaultTestPlan = {
@@ -53,13 +53,21 @@ const registryCompatibilityTestPlan: TestPlan[] = [
5353
configName: 'azure-registry-scoped',
5454
testFeatureId: 'privatedevcontainercli.azurecr.io/features/rabbit',
5555
useAuthStrategy: AuthStrategy.DockerConfigAuthFile,
56-
authCredentialEnvSecret: 'FEATURES_TEST__AZURE_REGISTRY_SCOPED_CREDENTIAL',
56+
authStrategyKey: 'FEATURES_TEST__AZURE_REGISTRY_SCOPED_CREDENTIAL',
5757
testCommand: 'rabbit',
5858
testCommandResult: /rabbit-is-the-best-animal/,
59+
},
60+
// Via GHCR visibility settings, this repo's GitHub Actions CI should be able to access this Feature via its GITHUB_TOKEN.
61+
{
62+
name: 'Private access of GHCR via an environment GITHUB_TOKEN',
63+
configName: 'github-private',
64+
testFeatureId: 'ghcr.io/devcontainers/private-feature-set-for-tests/color',
65+
useAuthStrategy: AuthStrategy.GitHubToken,
66+
authStrategyKey: 'RUNNING_IN_DEVCONTAINERS_CLI_REPO_CI'
5967
}
6068
];
6169

62-
function constructAuthFromStrategy(tmpFolder: string, authStrategy: AuthStrategy, authCredentialEnvSecret?: string): string | undefined {
70+
function constructAuthFromStrategy(tmpFolder: string, authStrategy: AuthStrategy, authStrategyKey?: string): string | undefined {
6371
const generateAuthFolder = () => {
6472
const randomChars = Math.random().toString(36).substring(2, 6);
6573
const tmpAuthFolder = path.join(tmpFolder, randomChars, 'auth');
@@ -69,12 +77,14 @@ function constructAuthFromStrategy(tmpFolder: string, authStrategy: AuthStrategy
6977

7078
switch (authStrategy) {
7179
case AuthStrategy.Anonymous:
80+
case AuthStrategy.GitHubToken:
7281
return;
7382
case AuthStrategy.DockerConfigAuthFile:
74-
if (!authCredentialEnvSecret) {
83+
// Format: registry|username|passwordOrToken
84+
if (!authStrategyKey) {
7585
return;
7686
}
77-
const split = process.env[authCredentialEnvSecret]?.split('|');
87+
const split = process.env[authStrategyKey]?.split('|');
7888
if (!split || split.length !== 3) {
7989
return;
8090
}
@@ -103,18 +113,18 @@ describe('Registry Compatibility', function () {
103113
await shellExec(`npm --prefix ${tmp} install devcontainers-cli-${pkg.version}.tgz`);
104114
});
105115

106-
registryCompatibilityTestPlan.forEach(({ name, configName, testFeatureId, testCommand, testCommandResult, useAuthStrategy, authCredentialEnvSecret }) => {
116+
registryCompatibilityTestPlan.forEach(({ name, configName, testFeatureId, testCommand, testCommandResult, useAuthStrategy, authStrategyKey }) => {
107117
this.timeout('120s');
108118
describe(name, async function () {
109-
((authCredentialEnvSecret && !process.env[authCredentialEnvSecret]) ? describe.skip : describe)('devcontainer up', async function () {
119+
((authStrategyKey && !process.env[authStrategyKey]) ? describe.skip : describe)('devcontainer up', async function () {
110120

111-
const authFolder = constructAuthFromStrategy(tmp, useAuthStrategy ?? AuthStrategy.Anonymous, authCredentialEnvSecret);
121+
const authFolder = constructAuthFromStrategy(tmp, useAuthStrategy ?? AuthStrategy.Anonymous, authStrategyKey) || '/fake-path';
112122

113123
let containerId: string | null = null;
114124
const testFolder = `${__dirname}/configs/registry-compatibility/${configName}`;
115125

116126
before(async () => containerId = (await devContainerUp(cli, testFolder, {
117-
'logLevel': 'trace', prefix: authFolder ? `DOCKER_CONFIG=${authFolder}` : undefined
127+
'logLevel': 'trace', prefix: `DOCKER_CONFIG=${authFolder}`
118128
})).containerId);
119129
after(async () => await devContainerDown({ containerId }));
120130

@@ -128,20 +138,15 @@ describe('Registry Compatibility', function () {
128138
});
129139
});
130140

131-
((authCredentialEnvSecret && !process.env[authCredentialEnvSecret]) ? describe.skip : describe)(`devcontainer features info manifest`, async function () {
141+
((authStrategyKey && !process.env[authStrategyKey]) ? describe.skip : describe)(`devcontainer features info manifest`, async function () {
132142

133-
const authFolder = constructAuthFromStrategy(tmp, useAuthStrategy ?? AuthStrategy.Anonymous, authCredentialEnvSecret);
143+
const authFolder = constructAuthFromStrategy(tmp, useAuthStrategy ?? AuthStrategy.Anonymous, authStrategyKey) || '/fake-path';
134144

135145
it('fetches manifest', async function () {
136146
let infoManifestResult: { stdout: string; stderr: string } | null = null;
137147
let success = false;
138148
try {
139-
if (authFolder) {
140-
infoManifestResult = await shellExec(`DOCKER_CONFIG=${authFolder} ${cli} features info manifest ${testFeatureId} --log-level trace`);
141-
142-
} else {
143-
infoManifestResult = await shellExec(`${cli} features info manifest ${testFeatureId} --log-level trace`);
144-
}
149+
infoManifestResult = await shellExec(`DOCKER_CONFIG=${authFolder} ${cli} features info manifest ${testFeatureId} --log-level trace`);
145150
success = true;
146151
} catch (error) {
147152
assert.fail('features info tags sub-command should not throw');

0 commit comments

Comments
 (0)