login-action/src/context.ts
Augustus Nguyen 4bcfaae325 Add Chainguard registry (cgr.dev) login support
Implement native OIDC-based authentication for Chainguard's container
registry, following the same pattern as the existing AWS ECR integration.

When registry is set to cgr.dev, the action automatically exchanges a
GitHub Actions OIDC token with Chainguard's STS endpoint for a short-lived
registry credential, removing the need for chainctl or long-lived pull tokens.

New inputs: chainguard (auto/true/false), chainguard-identity.

Signed-off-by: Augustus Nguyen <theflash28012002@gmail.com>
2026-04-21 11:20:09 +07:00

105 lines
3.0 KiB
TypeScript

import path from 'path';
import * as core from '@actions/core';
import * as yaml from 'js-yaml';
import {Buildx} from '@docker/actions-toolkit/lib/buildx/buildx.js';
import {Util} from '@docker/actions-toolkit/lib/util.js';
export interface Inputs {
registry: string;
username: string;
password: string;
scope: string;
ecr: string;
chainguard: string;
chainguardIdentity: string;
logout: boolean;
registryAuth: string;
}
export interface Auth {
registry: string;
username: string;
password: string;
scope: string;
ecr: string;
chainguard: string;
chainguardIdentity: string;
configDir: string;
}
export function getInputs(): Inputs {
return {
registry: core.getInput('registry'),
username: core.getInput('username'),
password: core.getInput('password'),
scope: core.getInput('scope'),
ecr: core.getInput('ecr'),
chainguard: core.getInput('chainguard'),
chainguardIdentity: core.getInput('chainguard-identity'),
logout: core.getBooleanInput('logout'),
registryAuth: core.getInput('registry-auth')
};
}
export function getAuthList(inputs: Inputs): Array<Auth> {
if (inputs.registryAuth && (inputs.registry || inputs.username || inputs.password || inputs.scope || inputs.ecr || inputs.chainguard || inputs.chainguardIdentity)) {
throw new Error('Cannot use registry-auth with other inputs');
}
let auths: Array<Auth> = [];
if (!inputs.registryAuth) {
const registry = inputs.registry || 'docker.io';
auths.push({
registry,
username: inputs.username,
password: inputs.password,
scope: inputs.scope,
ecr: inputs.ecr || 'auto',
chainguard: inputs.chainguard || 'auto',
chainguardIdentity: inputs.chainguardIdentity,
configDir: scopeToConfigDir(registry, inputs.scope)
});
} else {
auths = (yaml.load(inputs.registryAuth) as Array<Auth>).map(auth => {
if (auth.password) {
core.setSecret(auth.password);
}
const registry = auth.registry || 'docker.io';
return {
registry,
username: auth.username,
password: auth.password,
scope: auth.scope,
ecr: auth.ecr || 'auto',
chainguard: auth.chainguard || 'auto',
chainguardIdentity: auth.chainguardIdentity,
configDir: scopeToConfigDir(registry, auth.scope)
};
});
}
if (auths.length == 0) {
throw new Error('No registry to login');
}
return auths;
}
export function scopeToConfigDir(registry: string, scope?: string): string {
if (scopeDisabled() || !scope || scope === '') {
return '';
}
let configDir = path.join(Buildx.configDir, 'config', registry === 'docker.io' ? 'registry-1.docker.io' : registry);
if (scope.startsWith('@')) {
configDir += scope;
} else {
configDir = path.join(configDir, scope);
}
return configDir;
}
function scopeDisabled(): boolean {
if (process.env.DOCKER_LOGIN_SCOPE_DISABLED) {
return Util.parseBool(process.env.DOCKER_LOGIN_SCOPE_DISABLED);
}
return false;
}