Emit a better error when OIDC information is missing (#81)
This commit is contained in:
parent
1618f1c032
commit
ccc7806970
2
dist/main/index.js
vendored
2
dist/main/index.js
vendored
File diff suppressed because one or more lines are too long
@ -25,6 +25,9 @@ interface WorkloadIdentityClientOptions {
|
||||
serviceAccount: string;
|
||||
token: string;
|
||||
audience: string;
|
||||
|
||||
oidcTokenRequestURL: string;
|
||||
oidcTokenRequestToken: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -38,12 +41,18 @@ export class WorkloadIdentityClient implements AuthClient {
|
||||
readonly #token: string;
|
||||
readonly #audience: string;
|
||||
|
||||
readonly #oidcTokenRequestURL: string;
|
||||
readonly #oidcTokenRequestToken: string;
|
||||
|
||||
constructor(opts: WorkloadIdentityClientOptions) {
|
||||
this.#providerID = opts.providerID;
|
||||
this.#serviceAccount = opts.serviceAccount;
|
||||
this.#token = opts.token;
|
||||
this.#audience = opts.audience;
|
||||
|
||||
this.#oidcTokenRequestURL = opts.oidcTokenRequestURL;
|
||||
this.#oidcTokenRequestToken = opts.oidcTokenRequestToken;
|
||||
|
||||
this.#projectID =
|
||||
opts.projectID || this.extractProjectIDFromServiceAccountEmail(this.#serviceAccount);
|
||||
}
|
||||
@ -173,21 +182,7 @@ export class WorkloadIdentityClient implements AuthClient {
|
||||
* set as GOOGLE_APPLICATION_CREDENTIALS for gcloud and client libraries.
|
||||
*/
|
||||
async createCredentialsFile(outputDir: string): Promise<string> {
|
||||
// Extract the request token and request URL from the environment. These
|
||||
// are only set when an id-token is requested and the submitter has
|
||||
// collaborator permissions.
|
||||
const requestToken = process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN;
|
||||
const requestURLRaw = process.env.ACTIONS_ID_TOKEN_REQUEST_URL;
|
||||
if (!requestToken || !requestURLRaw) {
|
||||
throw new Error(
|
||||
'GitHub Actions did not inject $ACTIONS_ID_TOKEN_REQUEST_TOKEN or ' +
|
||||
'$ACTIONS_ID_TOKEN_REQUEST_URL into this job. This most likely ' +
|
||||
'means the GitHub Actions workflow permissions are incorrect, or ' +
|
||||
'this job is being run from a fork. For more information, please ' +
|
||||
'see the GitHub documentation at https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token',
|
||||
);
|
||||
}
|
||||
const requestURL = new URL(requestURLRaw);
|
||||
const requestURL = new URL(this.#oidcTokenRequestURL);
|
||||
|
||||
// Append the audience value to the request.
|
||||
const params = requestURL.searchParams;
|
||||
@ -204,7 +199,7 @@ export class WorkloadIdentityClient implements AuthClient {
|
||||
credential_source: {
|
||||
url: requestURL,
|
||||
headers: {
|
||||
Authorization: `Bearer ${requestToken}`,
|
||||
Authorization: `Bearer ${this.#oidcTokenRequestToken}`,
|
||||
},
|
||||
format: {
|
||||
type: 'json',
|
||||
|
23
src/main.ts
23
src/main.ts
@ -16,9 +16,15 @@ import { BaseClient } from './base';
|
||||
import { buildDomainWideDelegationJWT, explodeStrings, parseDuration } from './utils';
|
||||
|
||||
const secretsWarning =
|
||||
'If you are specifying input values via GitHub secrets, ensure the secret ' +
|
||||
'is being injected into the environment. By default, secrets are not passed ' +
|
||||
'to workflows triggered from forks, including Dependabot.';
|
||||
`If you are specifying input values via GitHub secrets, ensure the secret ` +
|
||||
`is being injected into the environment. By default, secrets are not ` +
|
||||
`passed to workflows triggered from forks, including Dependabot.`;
|
||||
|
||||
const oidcWarning =
|
||||
`GitHub Actions did not inject $ACTIONS_ID_TOKEN_REQUEST_TOKEN or ` +
|
||||
`$ACTIONS_ID_TOKEN_REQUEST_URL into this job. This most likely means the ` +
|
||||
`GitHub Actions workflow permissions are incorrect, or this job is being ` +
|
||||
`run from a fork. For more information, please see https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token`;
|
||||
|
||||
/**
|
||||
* Executes the main action, documented inline.
|
||||
@ -61,6 +67,15 @@ async function run(): Promise<void> {
|
||||
// Instantiate the correct client based on the provided input parameters.
|
||||
let client: AuthClient;
|
||||
if (workloadIdentityProvider) {
|
||||
// If we're going to do the OIDC dance, we need to make sure these values
|
||||
// are set. If they aren't, core.getIDToken() will fail and so will
|
||||
// generating the credentials file.
|
||||
const oidcTokenRequestToken = process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN;
|
||||
const oidcTokenRequestURL = process.env.ACTIONS_ID_TOKEN_REQUEST_URL;
|
||||
if (!oidcTokenRequestToken || !oidcTokenRequestURL) {
|
||||
throw new Error(oidcWarning);
|
||||
}
|
||||
|
||||
const token = await getIDToken(audience);
|
||||
client = new WorkloadIdentityClient({
|
||||
projectID: projectID,
|
||||
@ -68,6 +83,8 @@ async function run(): Promise<void> {
|
||||
serviceAccount: serviceAccount,
|
||||
token: token,
|
||||
audience: audience,
|
||||
oidcTokenRequestToken: oidcTokenRequestToken,
|
||||
oidcTokenRequestURL: oidcTokenRequestURL,
|
||||
});
|
||||
} else {
|
||||
client = new CredentialsJSONClient({
|
||||
|
@ -15,6 +15,8 @@ describe('WorkloadIdentityClient', () => {
|
||||
token: 'my-token',
|
||||
serviceAccount: 'my-service@my-project.iam.gserviceaccount.com',
|
||||
audience: 'my-aud',
|
||||
oidcTokenRequestURL: 'https://example.com/',
|
||||
oidcTokenRequestToken: 'token',
|
||||
});
|
||||
|
||||
const result = await client.getProjectID();
|
||||
@ -28,6 +30,8 @@ describe('WorkloadIdentityClient', () => {
|
||||
token: 'my-token',
|
||||
serviceAccount: 'my-service@my-project.iam.gserviceaccount.com',
|
||||
audience: 'my-aud',
|
||||
oidcTokenRequestURL: 'https://example.com/',
|
||||
oidcTokenRequestToken: 'token',
|
||||
});
|
||||
|
||||
const result = await client.getProjectID();
|
||||
@ -41,6 +45,8 @@ describe('WorkloadIdentityClient', () => {
|
||||
token: 'my-token',
|
||||
serviceAccount: 'my-service@developers.google.com',
|
||||
audience: 'my-aud',
|
||||
oidcTokenRequestURL: 'https://example.com/',
|
||||
oidcTokenRequestToken: 'token',
|
||||
});
|
||||
};
|
||||
return expect(fn).to.throw(Error);
|
||||
@ -55,6 +61,8 @@ describe('WorkloadIdentityClient', () => {
|
||||
serviceAccount: 'my-service@my-project.iam.gserviceaccount.com',
|
||||
token: 'my-token',
|
||||
audience: 'my-aud',
|
||||
oidcTokenRequestURL: 'https://example.com/',
|
||||
oidcTokenRequestToken: 'token',
|
||||
});
|
||||
const result = await client.getServiceAccount();
|
||||
expect(result).to.eq('my-service@my-project.iam.gserviceaccount.com');
|
||||
@ -63,9 +71,6 @@ describe('WorkloadIdentityClient', () => {
|
||||
|
||||
describe('#createCredentialsFile', () => {
|
||||
it('writes the file', async () => {
|
||||
process.env.ACTIONS_ID_TOKEN_REQUEST_URL = 'https://actions-token.url';
|
||||
process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'github-token';
|
||||
|
||||
const tmp = tmpdir();
|
||||
const client = new WorkloadIdentityClient({
|
||||
projectID: 'my-project',
|
||||
@ -73,6 +78,8 @@ describe('WorkloadIdentityClient', () => {
|
||||
serviceAccount: 'my-service@my-project.iam.gserviceaccount.com',
|
||||
token: 'my-token',
|
||||
audience: 'my-aud',
|
||||
oidcTokenRequestURL: 'https://example.com/',
|
||||
oidcTokenRequestToken: 'token',
|
||||
});
|
||||
|
||||
const exp = {
|
||||
@ -83,9 +90,9 @@ describe('WorkloadIdentityClient', () => {
|
||||
type: 'json',
|
||||
},
|
||||
headers: {
|
||||
Authorization: 'Bearer github-token',
|
||||
Authorization: 'Bearer token',
|
||||
},
|
||||
url: 'https://actions-token.url/?audience=my-aud',
|
||||
url: 'https://example.com/?audience=my-aud',
|
||||
},
|
||||
service_account_impersonation_url:
|
||||
'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/my-service@my-project.iam.gserviceaccount.com:generateAccessToken',
|
||||
|
Loading…
Reference in New Issue
Block a user