Compare commits
10 Commits
28d44ba259
...
0920706a19
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0920706a19 | ||
![]() |
ba79af0395 | ||
![]() |
bfaa66bd66 | ||
![]() |
d0822ad9bf | ||
![]() |
7b53cdc2a3 | ||
![]() |
a9cfddf5d2 | ||
![]() |
b011f3988e | ||
![]() |
71f986410d | ||
![]() |
0cd8f2e4e2 | ||
![]() |
332e0ba72f |
22
.github/workflows/draft-release.yml
vendored
22
.github/workflows/draft-release.yml
vendored
@ -1,17 +1,3 @@
|
||||
# Copyright 2023 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
name: 'Draft release'
|
||||
|
||||
on:
|
||||
@ -27,12 +13,14 @@ on:
|
||||
- 'minor'
|
||||
- 'patch'
|
||||
|
||||
permissions:
|
||||
contents: 'read'
|
||||
pull-requests: 'write'
|
||||
|
||||
jobs:
|
||||
draft-release:
|
||||
name: 'Draft release'
|
||||
uses: 'google-github-actions/.github/.github/workflows/draft-release.yml@v0'
|
||||
uses: 'google-github-actions/.github/.github/workflows/draft-release.yml@v3' # ratchet:exclude
|
||||
with:
|
||||
version_strategy: '${{ github.event.inputs.version_strategy }}'
|
||||
# secrets must be explicitly passed to reusable workflows https://docs.github.com/en/enterprise-cloud@latest/actions/using-workflows/reusing-workflows#using-inputs-and-secrets-in-a-reusable-workflow
|
||||
secrets:
|
||||
ACTIONS_BOT_TOKEN: '${{ secrets.ACTIONS_BOT_TOKEN }}'
|
||||
|
4
.github/workflows/publish.yml
vendored
4
.github/workflows/publish.yml
vendored
@ -16,10 +16,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871' # ratchet:actions/checkout@v4
|
||||
uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
|
||||
|
||||
- name: 'Publish'
|
||||
id: 'publish'
|
||||
uses: 'actions/publish-immutable-action@4b1aa5c1cde5fedc80d52746c9546cb5560e5f53' # ratchet:actions/publish-immutable-action@v0.0.3
|
||||
uses: 'actions/publish-immutable-action@4bc8754ffc40f27910afb20287dbbbb675a4e978' # ratchet:actions/publish-immutable-action@v0.0.4
|
||||
with:
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
|
24
.github/workflows/release.yml
vendored
24
.github/workflows/release.yml
vendored
@ -1,17 +1,3 @@
|
||||
# Copyright 2023 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
name: 'Release'
|
||||
|
||||
on:
|
||||
@ -20,12 +6,12 @@ on:
|
||||
- 'main'
|
||||
- 'release/**/*'
|
||||
|
||||
permissions:
|
||||
contents: 'read'
|
||||
packages: 'write'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
if: |-
|
||||
${{ startsWith(github.event.head_commit.message, 'Release: v') }}
|
||||
name: 'Release'
|
||||
uses: 'google-github-actions/.github/.github/workflows/release.yml@v1' # ratchet:exclude
|
||||
# secrets must be explicitly passed to reusable workflows https://docs.github.com/en/enterprise-cloud@latest/actions/using-workflows/reusing-workflows\#using-inputs-and-secrets-in-a-reusable-workflow
|
||||
uses: 'google-github-actions/.github/.github/workflows/release.yml@v3' # ratchet:exclude
|
||||
secrets:
|
||||
ACTIONS_BOT_TOKEN: '${{ secrets.ACTIONS_BOT_TOKEN }}'
|
||||
|
32
.github/workflows/test.yml
vendored
32
.github/workflows/test.yml
vendored
@ -33,15 +33,19 @@ defaults:
|
||||
run:
|
||||
shell: 'bash'
|
||||
|
||||
permissions:
|
||||
contents: 'read'
|
||||
statuses: 'write'
|
||||
|
||||
jobs:
|
||||
unit:
|
||||
name: 'unit'
|
||||
runs-on: 'ubuntu-latest'
|
||||
|
||||
steps:
|
||||
- uses: 'actions/checkout@v4'
|
||||
- uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
|
||||
|
||||
- uses: 'actions/setup-node@v4'
|
||||
- uses: 'actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a' # ratchet:actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
|
||||
@ -74,9 +78,9 @@ jobs:
|
||||
id-token: 'write'
|
||||
|
||||
steps:
|
||||
- uses: 'actions/checkout@v4'
|
||||
- uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
|
||||
|
||||
- uses: 'actions/setup-node@v4'
|
||||
- uses: 'actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a' # ratchet:actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
|
||||
@ -99,7 +103,7 @@ jobs:
|
||||
--fail \
|
||||
--header "Authorization: Bearer ${{ steps.auth-default.outputs.auth_token }}"
|
||||
|
||||
- uses: 'google-github-actions/setup-gcloud@v2'
|
||||
- uses: 'google-github-actions/setup-gcloud@main' # ratchet:exclude
|
||||
with:
|
||||
version: '>= 363.0.0'
|
||||
|
||||
@ -127,9 +131,9 @@ jobs:
|
||||
id-token: 'write'
|
||||
|
||||
steps:
|
||||
- uses: 'actions/checkout@v4'
|
||||
- uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
|
||||
|
||||
- uses: 'actions/setup-node@v4'
|
||||
- uses: 'actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a' # ratchet:actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
|
||||
@ -143,7 +147,7 @@ jobs:
|
||||
workload_identity_provider: '${{ vars.WIF_PROVIDER_NAME }}'
|
||||
service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
|
||||
|
||||
- uses: 'google-github-actions/setup-gcloud@v2'
|
||||
- uses: 'google-github-actions/setup-gcloud@main' # ratchet:exclude
|
||||
with:
|
||||
version: '>= 363.0.0'
|
||||
|
||||
@ -195,9 +199,9 @@ jobs:
|
||||
- 'macos-latest'
|
||||
|
||||
steps:
|
||||
- uses: 'actions/checkout@v4'
|
||||
- uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
|
||||
|
||||
- uses: 'actions/setup-node@v4'
|
||||
- uses: 'actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a' # ratchet:actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
|
||||
@ -210,7 +214,7 @@ jobs:
|
||||
with:
|
||||
credentials_json: '${{ secrets.SERVICE_ACCOUNT_KEY_JSON }}'
|
||||
|
||||
- uses: 'google-github-actions/setup-gcloud@v2'
|
||||
- uses: 'google-github-actions/setup-gcloud@main' # ratchet:exclude
|
||||
with:
|
||||
version: '>= 363.0.0'
|
||||
|
||||
@ -256,9 +260,9 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: 'actions/checkout@v4'
|
||||
- uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
|
||||
|
||||
- uses: 'actions/setup-node@v4'
|
||||
- uses: 'actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a' # ratchet:actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
|
||||
@ -271,7 +275,7 @@ jobs:
|
||||
credentials_json: '${{ secrets.SERVICE_ACCOUNT_KEY_JSON }}'
|
||||
|
||||
- name: 'docker'
|
||||
uses: 'docker://alpine:3'
|
||||
uses: 'docker://index.docker.io/library/alpine@sha256:56fa17d2a7e7f168a043a2712e63aed1f8543aeafdcee47c58dcffe38ed51099' # ratchet:docker://alpine:3
|
||||
with:
|
||||
entrypoint: '/bin/sh'
|
||||
args: '-euc "test -n "${GOOGLE_APPLICATION_CREDENTIALS}" && test -r "${GOOGLE_APPLICATION_CREDENTIALS}"'
|
||||
|
2
.github/workflows/troubleshooting.yml
vendored
2
.github/workflows/troubleshooting.yml
vendored
@ -27,7 +27,7 @@ jobs:
|
||||
runs-on: 'ubuntu-latest'
|
||||
|
||||
steps:
|
||||
- uses: 'actions/github-script@v7'
|
||||
- uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea' # ratchet:actions/github-script@v7
|
||||
with:
|
||||
script: |-
|
||||
const msg =
|
||||
|
@ -84,6 +84,12 @@ For more usage options, see the [examples](docs/EXAMPLES.md).
|
||||
> SDK](https://github.com/firebase/firebase-admin-node/issues/1377). Use Service
|
||||
> Account Key JSON authentication instead.
|
||||
|
||||
> [!WARNING]
|
||||
>
|
||||
> As of the time of this writing, the GitHub OIDC token expires in 5 minutes,
|
||||
> which means any derived credentials also expire in 5 minutes.
|
||||
|
||||
|
||||
The following inputs are for _authenticating_ to Google Cloud via Workload
|
||||
Identity Federation.
|
||||
|
||||
@ -316,7 +322,6 @@ regardless of the authentication mechanism.
|
||||
"token_format" is "id_token".
|
||||
|
||||
|
||||
|
||||
<a id="setup"></a>
|
||||
## Setup
|
||||
|
||||
|
@ -56,7 +56,7 @@ inputs:
|
||||
description: |-
|
||||
If true, the action will securely generate a credentials file which can be
|
||||
used for authentication via gcloud and Google Cloud SDKs.
|
||||
default: true
|
||||
default: 'true'
|
||||
required: false
|
||||
export_environment_variables:
|
||||
description: |-
|
||||
@ -79,7 +79,7 @@ inputs:
|
||||
If false, the action will not export any environment variables, meaning
|
||||
future steps are unlikely to be automatically authenticated to Google
|
||||
Cloud.
|
||||
default: true
|
||||
default: 'true'
|
||||
required: false
|
||||
token_format:
|
||||
description: |-
|
||||
@ -113,7 +113,7 @@ inputs:
|
||||
If true, the action will remove any created credentials from the
|
||||
filesystem upon completion. This only applies if "create_credentials_file"
|
||||
is true.
|
||||
default: true
|
||||
default: 'true'
|
||||
required: false
|
||||
|
||||
# access token params
|
||||
@ -175,7 +175,7 @@ inputs:
|
||||
generated token. If true, the token will contain "email" and
|
||||
"email_verified" claims. This is only valid when "token_format" is
|
||||
"id_token".
|
||||
default: false
|
||||
default: 'false'
|
||||
required: false
|
||||
|
||||
outputs:
|
||||
|
6
dist/main/index.js
vendored
6
dist/main/index.js
vendored
File diff suppressed because one or more lines are too long
6
dist/post/index.js
vendored
6
dist/post/index.js
vendored
File diff suppressed because one or more lines are too long
@ -187,6 +187,69 @@ jobs:
|
||||
run: |-
|
||||
curl https://myapp-uvehjacqzq.a.run.app \
|
||||
--header "Authorization: Bearer ${{ steps.auth.outputs.id_token }}"
|
||||
|
||||
# Example of using ID token in Python code
|
||||
- id: 'python-example'
|
||||
run: |-
|
||||
python -c "
|
||||
import os
|
||||
import requests
|
||||
|
||||
# ID token is available as environment variable
|
||||
id_token = os.environ.get('GOOGLE_ID_TOKEN', '${{ steps.auth.outputs.id_token }}')
|
||||
|
||||
# Use the token to invoke a Cloud Run service
|
||||
response = requests.get(
|
||||
'https://myapp-uvehjacqzq.a.run.app',
|
||||
headers={'Authorization': f'Bearer {id_token}'}
|
||||
)
|
||||
print(response.text)
|
||||
"
|
||||
```
|
||||
|
||||
### Using Default Credentials with Scopes in Python
|
||||
|
||||
When using Workload Identity Federation with Python libraries, you may need to
|
||||
add scopes before refreshing credentials:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
job_id:
|
||||
permissions:
|
||||
contents: 'read'
|
||||
id-token: 'write'
|
||||
|
||||
steps:
|
||||
- uses: 'actions/checkout@v4'
|
||||
|
||||
- id: 'auth'
|
||||
uses: 'google-github-actions/auth@v2'
|
||||
with:
|
||||
workload_identity_provider: 'projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider'
|
||||
service_account: 'my-service-account@my-project.iam.gserviceaccount.com'
|
||||
|
||||
- id: 'python-auth'
|
||||
run: |-
|
||||
python -c "
|
||||
from google.auth import default
|
||||
from google.auth.transport.requests import Request
|
||||
|
||||
# Get default credentials
|
||||
credentials, project = default()
|
||||
|
||||
# Add scopes before refreshing for impersonation
|
||||
credentials = credentials.with_scopes(
|
||||
['https://www.googleapis.com/auth/cloud-platform']
|
||||
)
|
||||
|
||||
# Refresh to get the token
|
||||
credentials.refresh(request=Request())
|
||||
|
||||
# Now you can use the credentials
|
||||
print(f'Access token: {credentials.token}')
|
||||
if hasattr(credentials, 'id_token'):
|
||||
print(f'ID token: {credentials.id_token}')
|
||||
"
|
||||
```
|
||||
|
||||
[github-markdown-toc]: https://github.blog/changelog/2021-04-13-table-of-contents-support-in-markdown-files/
|
||||
|
@ -230,6 +230,53 @@ tool like `jq`:
|
||||
cat credentials.json | jq -r tostring
|
||||
```
|
||||
|
||||
<a name="cannot-refresh"></a>
|
||||
|
||||
## Cannot refresh credentials to retrieve an ID token
|
||||
|
||||
If you get an error like:
|
||||
|
||||
```text
|
||||
google.auth.exceptions.RefreshError: ('Unable to acquire impersonated credentials', '{"error": {"code": 400, "message": "Request contains an invalid argument.", "status": "INVALID_ARGUMENT"}}')
|
||||
```
|
||||
|
||||
when trying to refresh credentials in Python code to get an ID token, this is
|
||||
usually because the credentials are missing required scopes. The Google Auth
|
||||
library requires scopes to be set when refreshing credentials for impersonation.
|
||||
|
||||
To fix this issue, add the required scopes before refreshing:
|
||||
|
||||
```python
|
||||
from google.auth import default
|
||||
from google.auth.transport.requests import Request
|
||||
|
||||
credentials, project = default()
|
||||
|
||||
# Add scopes before refreshing
|
||||
credentials = credentials.with_scopes(
|
||||
["https://www.googleapis.com/auth/cloud-platform"]
|
||||
)
|
||||
credentials.refresh(request=Request())
|
||||
|
||||
# Now you can access the ID token
|
||||
print(credentials.id_token)
|
||||
```
|
||||
|
||||
Alternatively, you can use the `token_format` parameter of this action to
|
||||
generate an ID token directly:
|
||||
|
||||
```yaml
|
||||
- uses: 'google-github-actions/auth@v2'
|
||||
with:
|
||||
workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
|
||||
service_account: ${{ secrets.WIF_SERVICE_ACCOUNT }}
|
||||
token_format: 'id_token'
|
||||
id_token_audience: 'https://example.com'
|
||||
```
|
||||
|
||||
This will export the ID token as an environment variable that you can use in
|
||||
your Python code.
|
||||
|
||||
## Organizational Policy Constraints
|
||||
|
||||
> **ℹ️ NOTE!** Your Google Cloud organization administrator controls these
|
||||
|
715
package-lock.json
generated
715
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
30
package.json
30
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@google-github-actions/auth",
|
||||
"version": "2.1.7",
|
||||
"version": "2.1.10",
|
||||
"description": "Authenticate to Google Cloud using OIDC tokens or JSON service account keys.",
|
||||
"main": "dist/main/index.js",
|
||||
"scripts": {
|
||||
@ -23,22 +23,22 @@
|
||||
"author": "GoogleCloudPlatform",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.1",
|
||||
"@actions/http-client": "^2.2.2",
|
||||
"@google-github-actions/actions-utils": "^0.8.3"
|
||||
"@actions/core": "^1.11.1",
|
||||
"@actions/http-client": "^2.2.3",
|
||||
"@google-github-actions/actions-utils": "^0.8.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.1.0",
|
||||
"@eslint/js": "^9.9.0",
|
||||
"@types/node": "^22.4.1",
|
||||
"@vercel/ncc": "^0.38.1",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"eslint": "^9.9.0",
|
||||
"prettier": "^3.3.3",
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "^9.25.1",
|
||||
"@types/node": "^22.14.1",
|
||||
"@vercel/ncc": "^0.38.3",
|
||||
"eslint-config-prettier": "^10.1.2",
|
||||
"eslint-plugin-prettier": "^5.2.6",
|
||||
"eslint": "^9.25.1",
|
||||
"prettier": "^3.5.3",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript-eslint": "^8.2.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.2.0",
|
||||
"typescript": "^5.5.4"
|
||||
"typescript-eslint": "^8.31.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.31.0",
|
||||
"typescript": "^5.8.3"
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ import { join as pathjoin } from 'path';
|
||||
|
||||
import {
|
||||
exportVariable,
|
||||
getBooleanInput,
|
||||
getIDToken,
|
||||
getInput,
|
||||
setFailed,
|
||||
@ -29,6 +28,7 @@ import {
|
||||
isEmptyDir,
|
||||
isPinnedToHead,
|
||||
parseMultilineCSV,
|
||||
parseBoolean,
|
||||
parseDuration,
|
||||
pinnedToHeadWarning,
|
||||
} from '@google-github-actions/actions-utils';
|
||||
@ -79,8 +79,8 @@ export async function run(logger: Logger) {
|
||||
const oidcTokenAudience =
|
||||
getInput(`audience`) || `https://iam.googleapis.com/${workloadIdentityProvider}`;
|
||||
const credentialsJSON = getInput(`credentials_json`);
|
||||
const createCredentialsFile = getBooleanInput(`create_credentials_file`);
|
||||
const exportEnvironmentVariables = getBooleanInput(`export_environment_variables`);
|
||||
const createCredentialsFile = parseBoolean(getInput(`create_credentials_file`));
|
||||
const exportEnvironmentVariables = parseBoolean(getInput(`export_environment_variables`));
|
||||
const tokenFormat = getInput(`token_format`);
|
||||
const delegates = parseMultilineCSV(getInput(`delegates`));
|
||||
const universe = getInput(`universe`);
|
||||
@ -301,7 +301,7 @@ export async function run(logger: Logger) {
|
||||
logger.debug(`Creating id token`);
|
||||
|
||||
const idTokenAudience = getInput('id_token_audience', { required: true });
|
||||
const idTokenIncludeEmail = getBooleanInput('id_token_include_email');
|
||||
const idTokenIncludeEmail = parseBoolean(getInput('id_token_include_email'));
|
||||
|
||||
// Ensure a service_account was provided if using WIF.
|
||||
if (!serviceAccount) {
|
||||
|
@ -12,21 +12,21 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { getBooleanInput, setFailed } from '@actions/core';
|
||||
import { getInput, setFailed } from '@actions/core';
|
||||
|
||||
import { errorMessage, forceRemove } from '@google-github-actions/actions-utils';
|
||||
import { errorMessage, forceRemove, parseBoolean } from '@google-github-actions/actions-utils';
|
||||
|
||||
import { Logger } from './logger';
|
||||
|
||||
export async function run(logger: Logger) {
|
||||
try {
|
||||
const createCredentials = getBooleanInput('create_credentials_file');
|
||||
const createCredentials = parseBoolean(getInput('create_credentials_file'));
|
||||
if (!createCredentials) {
|
||||
logger.info(`Skipping credential cleanup - "create_credentials_file" is false.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const cleanupCredentials = getBooleanInput('cleanup_credentials');
|
||||
const cleanupCredentials = parseBoolean(getInput('cleanup_credentials'));
|
||||
if (!cleanupCredentials) {
|
||||
logger.info(`Skipping credential cleanup - "cleanup_credentials" is false.`);
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user