Skip to content

Commit

Permalink
feat: authenticate with ghcr docker credentials (#854)
Browse files Browse the repository at this point in the history
This adds the ability to authenticate with the GitHub Container Registry (GHCR) in docker asset publishing steps.

closes #843
  • Loading branch information
corymhall authored Feb 1, 2024
1 parent d8dd921 commit 2535ddd
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 16 deletions.
30 changes: 24 additions & 6 deletions API.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,9 @@ const pipeline = new GitHubWorkflow(app, 'Pipeline', {
// Authenticate to ECR
DockerCredential.ecr('<account-id>.dkr.ecr.<aws-region>.amazonaws.com'),

// Authenticate to GHCR
DockerCredential.ghcr(),

// Authenticate to DockerHub
DockerCredential.dockerHub({
// These properties are defaults; feel free to omit
Expand Down
32 changes: 27 additions & 5 deletions src/docker-credentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ export class DockerCredential {
* found in your GitHub Secrets under these default keys.
*/
public static dockerHub(creds: DockerHubCredentialSecrets = {}): DockerCredential {
const username = creds.usernameKey ?? 'DOCKERHUB_USERNAME';
const password = creds.personalAccessTokenKey ?? 'DOCKERHUB_TOKEN';
return new DockerCredential(
'docker',
undefined,
creds.usernameKey ?? 'DOCKERHUB_USERNAME',
creds.personalAccessTokenKey ?? 'DOCKERHUB_TOKEN',
`\${{ secrets.${username} }}`,
`\${{ secrets.${password} }}`,
);
}

Expand All @@ -38,6 +40,21 @@ export class DockerCredential {
return new DockerCredential('ecr', registry);
}

/**
* Create a credential for the GitHub Container Registry (GHCR).
*
* For more information on authenticating to GHCR,
* @see https://docs.github.com/en/packages/managing-github-packages-using-github-actions-workflows/publishing-and-installing-a-package-with-github-actions
*/
public static ghcr(): DockerCredential {
return new DockerCredential(
'ghcr',
'ghcr.io',
'\${{ github.actor }}',
'\${{ secrets.GITHUB_TOKEN }}',
);
}

/**
* Create a credential for a custom registry. This method assumes that you will have long-lived
* GitHub Secrets stored under the usernameKey and passwordKey that will authenticate to the
Expand All @@ -46,14 +63,19 @@ export class DockerCredential {
* @see https://github.com/marketplace/actions/docker-login
*/
public static customRegistry(registry: string, creds: ExternalDockerCredentialSecrets): DockerCredential {
return new DockerCredential('custom', registry, creds.usernameKey, creds.passwordKey);
return new DockerCredential(
'custom',
registry,
`\${{ secrets.${creds.usernameKey} }}`,
`\${{ secrets.${creds.passwordKey} }}`,
);
}

private constructor(
readonly name: string,
readonly registry?: string,
readonly usernameKey?: string,
readonly passwordKey?: string,
readonly username?: string,
readonly password?: string,
) {}
}

Expand Down
19 changes: 14 additions & 5 deletions src/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ export class GitHubWorkflow extends PipelineBase {
}
> = {};
private readonly jobSettings?: JobSettings;
private readonly dockerAssetJobSettings?: DockerAssetJobSettings;
private dockerAssetJobSettings?: DockerAssetJobSettings;
// in order to keep track of if this pipeline has been built so we can
// catch later calls to addWave() or addStage()
private builtGH = false;
Expand Down Expand Up @@ -826,8 +826,8 @@ export class GitHubWorkflow extends PipelineBase {

if (dockerCredential.name === 'docker') {
params = {
username: `\${{ secrets.${dockerCredential.usernameKey} }}`,
password: `\${{ secrets.${dockerCredential.passwordKey} }}`,
username: dockerCredential.username,
password: dockerCredential.password,
};
} else if (dockerCredential.name === 'ecr') {
params = {
Expand All @@ -836,8 +836,17 @@ export class GitHubWorkflow extends PipelineBase {
} else {
params = {
registry: dockerCredential.registry,
username: `\${{ secrets.${dockerCredential.usernameKey} }}`,
password: `\${{ secrets.${dockerCredential.passwordKey} }}`,
username: dockerCredential.username,
password: dockerCredential.password,
};
}
if (dockerCredential.name === 'ghcr') {
this.dockerAssetJobSettings = {
...this.dockerAssetJobSettings,
permissions: {
...this.dockerAssetJobSettings?.permissions,
packages: github.JobPermission.READ,
},
};
}

Expand Down
22 changes: 22 additions & 0 deletions test/docker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,28 @@ describe('correct format for docker credentials:', () => {
});
const file = fs.readFileSync(github.workflowPath, 'utf-8');
const workflow = YAML.parse(file);
const permissions = workflow.jobs['Assets-DockerAsset1'].permissions;
expect(permissions).toEqual({
'contents': 'read',
'id-token': 'none',
'packages': 'read',
});
});

test('ghcr registry', () => {
const github = createDockerGithubWorkflow(app, [DockerCredential.ghcr()]);
const file = fs.readFileSync(github.workflowPath, 'utf-8');
const workflow = YAML.parse(file);
const steps = findStepByJobAndUses(workflow, 'Assets-DockerAsset1', 'docker/login-action@v2');

expect(steps[0]).toEqual({
uses: 'docker/login-action@v2',
with: {
registry: 'ghcr.io',
username: '${{ github.actor }}',
password: '${{ secrets.GITHUB_TOKEN }}',
},
});

const permissions = workflow.jobs['Assets-DockerAsset1'].permissions;
expect(permissions).toEqual({
Expand Down

0 comments on commit 2535ddd

Please sign in to comment.