mirror of
https://github.com/aws-actions/configure-aws-credentials.git
synced 2026-06-05 19:53:32 +00:00
Compare commits
17 commits
kellerkt/c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
037dd16322 |
||
|
|
89a34d9b83 |
||
|
|
d63f12fba5 |
||
|
|
aefb6ea018 |
||
|
|
bf27562715 | ||
|
|
4f3ef32554 |
||
|
|
26b365ff2f |
||
|
|
262ce4cfb5 |
||
|
|
e7f100cf4c |
||
|
|
bbbffeab00 | ||
|
|
d6f5dc331b |
||
|
|
12014c0798 |
||
|
|
4ab3589ed2 |
||
|
|
99214aa688 | ||
|
|
217d17914b |
||
|
|
5548f3441b | ||
|
|
77cd089899 |
12 changed files with 9201 additions and 9227 deletions
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
".release-please-manifest.json": "4.0.2",
|
||||
"package.json": "6.0.0",
|
||||
".": "6.1.2"
|
||||
".": "6.2.0"
|
||||
}
|
||||
|
|
|
|||
16
CHANGELOG.md
16
CHANGELOG.md
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
## [6.1.2](https://github.com/aws-actions/configure-aws-credentials/compare/v6.1.1...v6.1.2) (2026-05-26)
|
||||
|
||||
## [6.2.0](https://github.com/aws-actions/configure-aws-credentials/compare/v6.1.3...v6.2.0) (2026-06-01)
|
||||
|
||||
### Features
|
||||
|
||||
|
|
@ -14,11 +13,22 @@ All notable changes to this project will be documented in this file. See [standa
|
|||
* expose run id in STS client user-agent ([#1774](https://github.com/aws-actions/configure-aws-credentials/issues/1774)) ([29d1be3](https://github.com/aws-actions/configure-aws-credentials/commit/29d1be30273e7ef371d59fccf6ec54572c64ec89))
|
||||
* support custom STS endpoints ([#1762](https://github.com/aws-actions/configure-aws-credentials/issues/1762)) ([8d52d05](https://github.com/aws-actions/configure-aws-credentials/commit/8d52d05d7a4521fa52b39de50cb6114b12e5c332))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* skip credential check on output-env-credentials: false ([#1778](https://github.com/aws-actions/configure-aws-credentials/issues/1778)) ([58e7c47](https://github.com/aws-actions/configure-aws-credentials/commit/58e7c47adf77846879008deadfeeef8a6969fe6c))
|
||||
* assumeRole failing from session tag size too large ([#1808](https://github.com/aws-actions/configure-aws-credentials/issues/1808)) ([d6f5dc3](https://github.com/aws-actions/configure-aws-credentials/commit/d6f5dc331b44474b19a52caaf85fa4d637b13c8e))
|
||||
|
||||
## [6.1.3](https://github.com/aws-actions/configure-aws-credentials/compare/v6.1.2...v6.1.3) (2026-05-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix: allow kubelet token symlink in [#1805](https://github.com/aws-actions/configure-aws-credentials/issues/1805)
|
||||
|
||||
## [6.1.2](https://github.com/aws-actions/configure-aws-credentials/compare/v6.1.1...v6.1.2) (2026-05-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* additional filesystem checks ([#1799](https://github.com/aws-actions/configure-aws-credentials/issues/1799)) ([c39f282](https://github.com/aws-actions/configure-aws-credentials/commit/c39f282697aca8a78c522ecf1f7da9899a31432c))
|
||||
* skip credential check on output-env-credentials: false ([#1778](https://github.com/aws-actions/configure-aws-credentials/issues/1778)) ([58e7c47](https://github.com/aws-actions/configure-aws-credentials/commit/58e7c47adf77846879008deadfeeef8a6969fe6c))
|
||||
|
||||
## [6.1.1](https://github.com/aws-actions/configure-aws-credentials/compare/v6.1.0...v6.1.1) (2026-05-05)
|
||||
|
||||
|
|
|
|||
85
README.md
85
README.md
|
|
@ -168,6 +168,7 @@ detail.
|
|||
| role-session-name | Defaults to "GitHubActions", but may be changed if required. | No |
|
||||
| role-skip-session-tagging | Skips session tagging if set. | No |
|
||||
| transitive-tag-keys | Define a list of transitive tag keys to pass when assuming a role. | No |
|
||||
| custom-tags | Additional tags to apply to the assumed role session. Must be a JSON object provided as a string. Custom tags are not usable with OIDC or web identity token authentication. | No |
|
||||
| inline-session-policy | You may further restrict the assumed role policy by defining an inline policy here. | No |
|
||||
| managed-session-policies | You may further restrict the assumed role policy by specifying a managed policy here. | No |
|
||||
| output-credentials | When set, outputs fetched credentials as action step output. (Outputs aws-access-key-id, aws-secret-access-key, aws-session-token, aws-account-id, authenticated-arn, and aws-expiration). Defaults to false. | No |
|
||||
|
|
@ -180,6 +181,8 @@ detail.
|
|||
| allowed-account-ids | A comma-delimited list of expected AWS account IDs. The action will fail if we receive credentials for the wrong account. | No |
|
||||
| force-skip-oidc | When set, the action will skip using GitHub OIDC provider even if the id-token permission is set. | No |
|
||||
| action-timeout-s | Global timeout for the action in seconds. If set to a value greater than 0, the action will fail if it takes longer than this time to complete. | No |
|
||||
| no-proxy | Hosts to skip for the proxy configuration. | No |
|
||||
| sts-endpoint | Custom STS endpoint URL. Use this to point to an STS-compatible API (e.g. MinIO, LocalStack) instead of the default AWS STS endpoint for the region. | No |
|
||||
|
||||
</details>
|
||||
|
||||
|
|
@ -350,8 +353,7 @@ documentation for `GITHUB_` environment variable definitions][gh-env-vars])
|
|||
[gh-env-vars]:
|
||||
https://docs.github.com/en/actions/reference/workflows-and-actions/variables#default-environment-variables
|
||||
|
||||
**Protected tags** are always emitted when session tags are used, and cannot be
|
||||
overridden via `custom-tags`:
|
||||
**Default tags** are always emitted when session tags are used.
|
||||
|
||||
| Key | Value |
|
||||
| ---------- | ----------------- |
|
||||
|
|
@ -363,21 +365,24 @@ overridden via `custom-tags`:
|
|||
| Commit | GITHUB_SHA |
|
||||
| Branch | GITHUB_REF |
|
||||
|
||||
**Overrideable tags** are automatically added to the set of default session tags
|
||||
but may be overridden via `custom-tags`. AWS has a maximum limit of 50 session
|
||||
tags; tags from this list are dropped in reverse priority order if your
|
||||
`custom-tags` set plus the protected set exceeds this limit.
|
||||
**Droppable tags** are automatically added to the set of default session tags.
|
||||
If the session tags exceed the [packed size limit][packed-size-limit], these
|
||||
tags will be dropped, and the AssumeRole call will be retried. If it still
|
||||
fails, the action will error out. (It is difficult to predict the packed size
|
||||
before making the call, as session tags and session policies are compressed into
|
||||
a binary format as part of the call.)
|
||||
|
||||
| Key | Value | Priority |
|
||||
| --------------- | ----------------------- | -------- |
|
||||
| EventName | GITHUB_EVENT_NAME | 1 |
|
||||
| BaseRef | GITHUB_BASE_REF | 2 |
|
||||
| HeadRef | GITHUB_HEAD_REF | 3 |
|
||||
| RefName | GITHUB_REF_NAME | 4 |
|
||||
| RunId | GITHUB_RUN_ID | 5 |
|
||||
| RefType | GITHUB_REF_TYPE | 6 |
|
||||
| Job | GITHUB_JOB | 7 |
|
||||
| TriggeringActor | GITHUB_TRIGGERING_ACTOR | 8 |
|
||||
[packed-size-limit]:
|
||||
https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_know
|
||||
|
||||
| Key | Value |
|
||||
| --------------- | ----------------------- |
|
||||
| EventName | GITHUB_EVENT_NAME |
|
||||
| BaseRef | GITHUB_BASE_REF |
|
||||
| HeadRef | GITHUB_HEAD_REF |
|
||||
| RunId | GITHUB_RUN_ID |
|
||||
| Job | GITHUB_JOB |
|
||||
| TriggeringActor | GITHUB_TRIGGERING_ACTOR |
|
||||
|
||||
Tags whose source environment variable is unset are omitted (e.g., `BaseRef` and
|
||||
`HeadRef` are only set on `pull_request` events).
|
||||
|
|
@ -385,21 +390,21 @@ Tags whose source environment variable is unset are omitted (e.g., `BaseRef` and
|
|||
_Note: all tag values must conform to
|
||||
[the tag requirements][sts-tag-requirements].
|
||||
Values longer than 256 characters will be truncated, and characters outside the
|
||||
allowed set will be replaced with an underscore (`_`).\_
|
||||
allowed set will be replaced with an underscore (`_`)._
|
||||
|
||||
[sts-tag-requirements]:
|
||||
https://docs.aws.amazon.com/STS/latest/APIReference/API_Tag.html
|
||||
|
||||
The action will use session tagging by default unless you are using OIDC.
|
||||
The action will use session tagging by default unless you are using OIDC or a
|
||||
Web Identify Token File.
|
||||
|
||||
To [forward session tags to subsequent sessions in a role
|
||||
chain][session-tag-chaining], you can use
|
||||
chain][session-tag-chaining], you can use the `transitive-tag-keys` input to
|
||||
specify the keys of the tags to be passed.
|
||||
|
||||
[session-tag-chaining]:
|
||||
https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining
|
||||
|
||||
the `transitive-tag-keys` input to specify the keys of the tags to be passed.
|
||||
|
||||
_Note that all subsequent roles in the chain must have
|
||||
`role-skip-session-tagging` set to `true`_
|
||||
|
||||
|
|
@ -416,9 +421,10 @@ with:
|
|||
### Custom session tags
|
||||
|
||||
You can add custom session tags using the `custom-tags` input, which accepts a
|
||||
JSON object. Custom tags cannot override protected tags, but they can override
|
||||
overrideable tags (in which case the overrideable tag's slot is freed for the
|
||||
next overrideable tag in the priority list, if any).
|
||||
JSON object. Custom tags cannot override existing tags. Note that AWS allows a
|
||||
maximum of 50 tags (so you can supply a maximum of 43 custom tags), although it
|
||||
is likely that you will exceed the [packed size limit][packed-size-limit]
|
||||
before you exceed the maximum number of tags.
|
||||
|
||||
```yaml
|
||||
uses: aws-actions/configure-aws-credentials@v6
|
||||
|
|
@ -584,7 +590,7 @@ claims ([1][gh-blog-oidc], [2][sub-claim-custom]).
|
|||
|
||||
> **Warning:** Avoid `ForAllValues:` in `Allow` statements. These operators
|
||||
> return true when the claim is absent or misspelled, which can lead to
|
||||
> uninended access. Instead, use `StringEquals` or `StringLike` operators to
|
||||
> unintended access. Instead, use `StringEquals` or `StringLike` operators to
|
||||
> check for specific claim values.
|
||||
|
||||
[least-privilege]:
|
||||
|
|
@ -617,6 +623,35 @@ For further information on OIDC and GitHub Actions, please see:
|
|||
- [GitHub docs: Configuring OpenID Connect in Amazon Web Services](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services)
|
||||
- [GitHub changelog: GitHub Actions: Secure cloud deployments with OpenID Connect](https://github.blog/changelog/2021-10-27-github-actions-secure-cloud-deployments-with-openid-connect/)
|
||||
|
||||
## Getting Credentials in AWS Self-Hosted Runners
|
||||
|
||||
If you are running GitHub Actions in a self-hosted runner using an AWS Service
|
||||
(such as Codebuild or EKS) and you have properly configured the service,
|
||||
credentials should be available by default; the AWS CLI will fetch credentials
|
||||
using the AWS_CONTAINER_CREDENTIALS_FULL_URI or
|
||||
AWS_CONTAINER_CREDENTIALS_RELATIVE_URI environment variables. However, you may
|
||||
still want to use this action if you need to export those credentials for use
|
||||
with other tools in your workflow. You may also want to use this action in
|
||||
scenarios where you need to use that 'default' role to assume another role.
|
||||
|
||||
To export credentials, simply run the action with `role-to-assume` set to the
|
||||
default role of the container.
|
||||
|
||||
To assume another role from the container's default role, use the
|
||||
`role-chaining: true` flag, so that the action fetches the default credentials
|
||||
from the environment before assuming the other role.
|
||||
|
||||
If you are using EKS Pod Identities and encountering an error related to the
|
||||
packed size of session tags, you must either run the action with
|
||||
`role-skip-session-tagging: true` to disable the tags set by the action, or
|
||||
[disable EKS session tagging][eks-disable-session-tagging] in the EKS settings
|
||||
to disable the tags that are automatically set by the EKS Pod Identity Service.
|
||||
Check the values of the action's session tags and the session tags that are
|
||||
added by EKS so you can keep the set of tags which is more useful to you.
|
||||
|
||||
[eks-disable-session-tagging]:
|
||||
https://docs.aws.amazon.com/eks/latest/userguide/pod-id-abac.html#pod-id-abac-tags
|
||||
|
||||
## Compatibility with non-GitHub Actions environments
|
||||
|
||||
This action has been sucessfully tested with
|
||||
|
|
|
|||
44
THIRD-PARTY
44
THIRD-PARTY
|
|
@ -644,7 +644,7 @@ Apache License
|
|||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- @aws-sdk/client-sts@3.1049.0
|
||||
- @aws-sdk/client-sts@3.1061.0
|
||||
|
||||
This package contains the following license:
|
||||
|
||||
|
|
@ -854,9 +854,9 @@ Apache License
|
|||
|
||||
The following npm packages may be included in this product:
|
||||
|
||||
- @aws-sdk/signature-v4-multi-region@3.996.27
|
||||
- @smithy/core@3.24.3
|
||||
- @smithy/types@4.14.2
|
||||
- @aws-sdk/signature-v4-multi-region@3.996.31
|
||||
- @smithy/core@3.24.6
|
||||
- @smithy/types@4.14.3
|
||||
|
||||
These packages each contain the following license:
|
||||
|
||||
|
|
@ -1254,7 +1254,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- @aws-sdk/core@3.974.12
|
||||
- @aws-sdk/core@3.974.17
|
||||
|
||||
This package contains the following license:
|
||||
|
||||
|
|
@ -1674,18 +1674,18 @@ Apache License
|
|||
|
||||
The following npm packages may be included in this product:
|
||||
|
||||
- @aws-sdk/credential-provider-env@3.972.38
|
||||
- @aws-sdk/credential-provider-ini@3.972.42
|
||||
- @aws-sdk/credential-provider-node@3.972.43
|
||||
- @aws-sdk/token-providers@3.1049.0
|
||||
- @aws-sdk/types@3.973.8
|
||||
- @aws-sdk/credential-provider-env@3.972.43
|
||||
- @aws-sdk/credential-provider-ini@3.972.48
|
||||
- @aws-sdk/credential-provider-node@3.972.50
|
||||
- @aws-sdk/token-providers@3.1060.0
|
||||
- @aws-sdk/types@3.973.10
|
||||
- @aws-sdk/util-locate-window@3.965.5
|
||||
- @aws-sdk/xml-builder@3.972.24
|
||||
- @smithy/credential-provider-imds@4.3.3
|
||||
- @smithy/fetch-http-handler@5.4.3
|
||||
- @aws-sdk/xml-builder@3.972.27
|
||||
- @smithy/credential-provider-imds@4.3.7
|
||||
- @smithy/fetch-http-handler@5.4.6
|
||||
- @smithy/is-array-buffer@2.2.0
|
||||
- @smithy/node-http-handler@4.7.3
|
||||
- @smithy/signature-v4@5.4.3
|
||||
- @smithy/node-http-handler@4.7.6
|
||||
- @smithy/signature-v4@5.4.6
|
||||
- @smithy/util-buffer-from@2.2.0
|
||||
- @smithy/util-utf8@2.3.0
|
||||
|
||||
|
|
@ -1897,9 +1897,9 @@ Apache License
|
|||
|
||||
The following npm packages may be included in this product:
|
||||
|
||||
- @aws-sdk/credential-provider-process@3.972.38
|
||||
- @aws-sdk/credential-provider-sso@3.972.42
|
||||
- @aws-sdk/credential-provider-web-identity@3.972.42
|
||||
- @aws-sdk/credential-provider-process@3.972.43
|
||||
- @aws-sdk/credential-provider-sso@3.972.47
|
||||
- @aws-sdk/credential-provider-web-identity@3.972.47
|
||||
|
||||
These packages each contain the following license:
|
||||
|
||||
|
|
@ -2109,9 +2109,9 @@ Apache License
|
|||
|
||||
The following npm packages may be included in this product:
|
||||
|
||||
- @aws-sdk/credential-provider-http@3.972.40
|
||||
- @aws-sdk/credential-provider-login@3.972.42
|
||||
- @aws-sdk/nested-clients@3.997.10
|
||||
- @aws-sdk/credential-provider-http@3.972.45
|
||||
- @aws-sdk/credential-provider-login@3.972.47
|
||||
- @aws-sdk/nested-clients@3.997.15
|
||||
|
||||
These packages each contain the following license:
|
||||
|
||||
|
|
@ -2335,7 +2335,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
The following npm packages may be included in this product:
|
||||
|
||||
- @nodable/entities@2.1.0
|
||||
- @nodable/entities@2.1.1
|
||||
- quickjs-wasi@2.2.0
|
||||
- xml-naming@0.1.0
|
||||
|
||||
|
|
|
|||
3891
dist/index.js
generated
vendored
3891
dist/index.js
generated
vendored
File diff suppressed because it is too large
Load diff
1038
package-lock.json
generated
1038
package-lock.json
generated
File diff suppressed because it is too large
Load diff
20
package.json
20
package.json
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "configure-aws-credentials",
|
||||
"description": "A GitHub Action to configure AWS credentials",
|
||||
"version": "6.1.1",
|
||||
"version": "6.2.0",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"lint": "biome check --error-on-warnings ./src ./test && markdownlint -i node_modules -i CHANGELOG.md '**/*.md'",
|
||||
|
|
@ -17,24 +17,24 @@
|
|||
"organization": true
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aws-sdk/credential-provider-env": "^3.972.38",
|
||||
"@biomejs/biome": "2.4.15",
|
||||
"@smithy/property-provider": "^4.3.3",
|
||||
"@types/node": "^25.9.0",
|
||||
"@vitest/coverage-v8": "^4.1.6",
|
||||
"@aws-sdk/credential-provider-env": "^3.972.39",
|
||||
"@biomejs/biome": "2.4.16",
|
||||
"@smithy/property-provider": "^4.3.6",
|
||||
"@types/node": "^25.9.1",
|
||||
"@vitest/coverage-v8": "4.1.8",
|
||||
"aws-sdk-client-mock": "^4.1.0",
|
||||
"esbuild": "^0.28.0",
|
||||
"generate-license-file": "^4.1.1",
|
||||
"generate-license-file": "^4.2.1",
|
||||
"json-schema": "^0.4.0",
|
||||
"markdownlint-cli": "^0.48.0",
|
||||
"memfs": "^4.57.2",
|
||||
"memfs": "^4.57.6",
|
||||
"standard-version": "^9.5.0",
|
||||
"typescript": "^6.0.3",
|
||||
"vitest": "^4.1.6"
|
||||
"vitest": "4.1.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": "^3.0.1",
|
||||
"@aws-sdk/client-sts": "^3.1049.0",
|
||||
"@aws-sdk/client-sts": "^3.1061.0",
|
||||
"@smithy/node-http-handler": "^4.7.3",
|
||||
"proxy-agent": "^8.0.1"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,7 +2,11 @@ import assert from 'node:assert';
|
|||
import path from 'node:path';
|
||||
import * as core from '@actions/core';
|
||||
import type { AssumeRoleCommandInput, STSClient, Tag } from '@aws-sdk/client-sts';
|
||||
import { AssumeRoleCommand, AssumeRoleWithWebIdentityCommand } from '@aws-sdk/client-sts';
|
||||
import {
|
||||
AssumeRoleCommand,
|
||||
AssumeRoleWithWebIdentityCommand,
|
||||
PackedPolicyTooLargeException,
|
||||
} from '@aws-sdk/client-sts';
|
||||
import type { CredentialsClient } from './CredentialsClient';
|
||||
import { errorMessage, isDefined, readFileUtf8, sanitizeGitHubVariables } from './helpers';
|
||||
|
||||
|
|
@ -42,6 +46,7 @@ async function assumeRoleWithWebIdentityTokenFile(
|
|||
core.info('Assuming role with web identity token file');
|
||||
try {
|
||||
delete params.Tags;
|
||||
delete params.TransitiveTagKeys;
|
||||
const creds = await client.send(
|
||||
new AssumeRoleWithWebIdentityCommand({
|
||||
...params,
|
||||
|
|
@ -60,6 +65,13 @@ async function assumeRoleWithCredentials(params: AssumeRoleCommandInput, client:
|
|||
const creds = await client.send(new AssumeRoleCommand({ ...params }));
|
||||
return creds;
|
||||
} catch (error) {
|
||||
if (error instanceof PackedPolicyTooLargeException) {
|
||||
core.info('Session tag size is too large; dropping droppable tags and retrying.');
|
||||
const droppableKeys = new Set(DROPPABLE_TAG_SOURCES.map((s) => s.key));
|
||||
params.Tags = params.Tags?.filter((tag) => !droppableKeys.has(tag.Key ?? ''));
|
||||
const creds = await client.send(new AssumeRoleCommand({ ...params }));
|
||||
return creds;
|
||||
}
|
||||
throw new Error(`Could not assume role with user credentials: ${errorMessage(error)}`);
|
||||
}
|
||||
}
|
||||
|
|
@ -86,8 +98,8 @@ const MAX_TAG_KEY_LENGTH = 128;
|
|||
const MAX_TAG_VALUE_LENGTH = 256;
|
||||
const MAX_SESSION_TAGS = 50;
|
||||
|
||||
// Identity/audit primitives. Always emitted and cannot be overridden by custom-tags.
|
||||
const PROTECTED_TAG_SOURCES: ReadonlyArray<{ key: string; envVar: string }> = [
|
||||
// Identity/audit primitives. Always emitted and cannot be dropped.
|
||||
const NON_DROPPABLE_TAG_SOURCES: ReadonlyArray<{ key: string; envVar: string }> = [
|
||||
{ key: 'Repository', envVar: 'GITHUB_REPOSITORY' },
|
||||
{ key: 'Workflow', envVar: 'GITHUB_WORKFLOW' },
|
||||
{ key: 'Action', envVar: 'GITHUB_ACTION' },
|
||||
|
|
@ -96,21 +108,22 @@ const PROTECTED_TAG_SOURCES: ReadonlyArray<{ key: string; envVar: string }> = [
|
|||
{ key: 'Branch', envVar: 'GITHUB_REF' },
|
||||
];
|
||||
|
||||
// Convenience metadata. Custom-tags may override (suppresses the default for that key).
|
||||
// Listed in priority order; lower-priority entries are dropped first if the user's custom-tags
|
||||
// would push the total above MAX_SESSION_TAGS.
|
||||
const OVERRIDEABLE_TAG_SOURCES_BY_PRIORITY: ReadonlyArray<{ key: string; envVar: string }> = [
|
||||
// Convenience metadata. If the AssumeRole call fails due to compressed size of
|
||||
// session tags being too large, we will drop these tags and retry once.
|
||||
const DROPPABLE_TAG_SOURCES: ReadonlyArray<{ key: string; envVar: string }> = [
|
||||
{ key: 'EventName', envVar: 'GITHUB_EVENT_NAME' },
|
||||
{ key: 'BaseRef', envVar: 'GITHUB_BASE_REF' },
|
||||
{ key: 'HeadRef', envVar: 'GITHUB_HEAD_REF' },
|
||||
{ key: 'RefName', envVar: 'GITHUB_REF_NAME' },
|
||||
{ key: 'RunId', envVar: 'GITHUB_RUN_ID' },
|
||||
{ key: 'RefType', envVar: 'GITHUB_REF_TYPE' },
|
||||
{ key: 'Job', envVar: 'GITHUB_JOB' },
|
||||
{ key: 'TriggeringActor', envVar: 'GITHUB_TRIGGERING_ACTOR' },
|
||||
];
|
||||
|
||||
const PROTECTED_TAG_KEYS = new Set<string>(['GitHub', ...PROTECTED_TAG_SOURCES.map((s) => s.key)]);
|
||||
const PROTECTED_TAG_KEYS = new Set<string>([
|
||||
'GitHub',
|
||||
...NON_DROPPABLE_TAG_SOURCES.map((s) => s.key),
|
||||
...DROPPABLE_TAG_SOURCES.map((s) => s.key),
|
||||
]);
|
||||
|
||||
export function parseAndValidateCustomTags(customTags: string, existingTags: Tag[]): Tag[] {
|
||||
let parsed: unknown;
|
||||
|
|
@ -197,7 +210,13 @@ export async function assumeRole(params: assumeRoleParams) {
|
|||
// Build session tags. Values are sanitized because the AWS tag value spec is more
|
||||
// restrictive than permissible characters in environment variables.
|
||||
const protectedTags: Tag[] = [{ Key: 'GitHub', Value: 'Actions' }];
|
||||
for (const { key, envVar } of PROTECTED_TAG_SOURCES) {
|
||||
for (const { key, envVar } of NON_DROPPABLE_TAG_SOURCES) {
|
||||
const value = process.env[envVar];
|
||||
if (value) {
|
||||
protectedTags.push({ Key: key, Value: sanitizeGitHubVariables(value) });
|
||||
}
|
||||
}
|
||||
for (const { key, envVar } of DROPPABLE_TAG_SOURCES) {
|
||||
const value = process.env[envVar];
|
||||
if (value) {
|
||||
protectedTags.push({ Key: key, Value: sanitizeGitHubVariables(value) });
|
||||
|
|
@ -205,26 +224,15 @@ export async function assumeRole(params: assumeRoleParams) {
|
|||
}
|
||||
|
||||
const parsedCustomTags: Tag[] = customTags ? parseAndValidateCustomTags(customTags, protectedTags) : [];
|
||||
const customTagKeys = new Set(parsedCustomTags.map((t) => t.Key));
|
||||
|
||||
const availableOverrideableSlots = MAX_SESSION_TAGS - protectedTags.length - parsedCustomTags.length;
|
||||
const overrideableTags: Tag[] = [];
|
||||
for (const { key, envVar } of OVERRIDEABLE_TAG_SOURCES_BY_PRIORITY) {
|
||||
if (overrideableTags.length >= availableOverrideableSlots) break;
|
||||
if (customTagKeys.has(key)) continue;
|
||||
const value = process.env[envVar];
|
||||
if (value) {
|
||||
overrideableTags.push({ Key: key, Value: sanitizeGitHubVariables(value) });
|
||||
}
|
||||
}
|
||||
|
||||
const tagArray: Tag[] = [...protectedTags, ...overrideableTags, ...parsedCustomTags];
|
||||
const tagArray: Tag[] = [...protectedTags, ...parsedCustomTags];
|
||||
|
||||
const tags = roleSkipSessionTagging ? undefined : tagArray;
|
||||
if (!tags) {
|
||||
core.debug('Role session tagging has been skipped.');
|
||||
} else {
|
||||
core.debug(`${tags.length} role session tags are being used:`);
|
||||
core.debug(JSON.stringify(tagArray));
|
||||
}
|
||||
|
||||
//only populate transitiveTagKeys array if user is actually using session tagging
|
||||
|
|
|
|||
|
|
@ -297,6 +297,20 @@ export function getBooleanInput(name: string, options?: core.InputOptions & { de
|
|||
// O_NOFOLLOW is undefined on Windows. This sets it to 0 if it's not defined.
|
||||
const O_NOFOLLOW: number = (fs.constants as { O_NOFOLLOW?: number }).O_NOFOLLOW ?? 0;
|
||||
|
||||
export function isAllowListed(filePath: string): boolean {
|
||||
// Kubelet projects service-account tokens through a symlink chain
|
||||
// (token -> ..data/token, ..data -> ..<timestamp>/). The containing path is
|
||||
// kubelet-controlled, so we allow symlink-following reads of this fixed
|
||||
// location only.
|
||||
const KUBERNETES_TOKEN_PATH_REGEX = /^\/var\/run\/secrets\/[^/]+\/serviceaccount\/token$/;
|
||||
|
||||
if (process.platform !== 'win32') {
|
||||
// No Kubernetes token paths on Windows
|
||||
return KUBERNETES_TOKEN_PATH_REGEX.test(path.posix.normalize(filePath));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isSymlink(filePath: string): boolean {
|
||||
try {
|
||||
return fs.lstatSync(filePath).isSymbolicLink();
|
||||
|
|
@ -328,10 +342,14 @@ function assertRegularFile(fd: number, filePath: string): void {
|
|||
// ELOOP: too many symbolic links (from NOFOLLOW)
|
||||
|
||||
export function readFileUtf8(filePath: string): string | null {
|
||||
refuseSymlinkOnPath(filePath);
|
||||
const allowSymlink = isAllowListed(filePath);
|
||||
if (!allowSymlink) {
|
||||
refuseSymlinkOnPath(filePath);
|
||||
}
|
||||
const openFlags = fs.constants.O_RDONLY | (allowSymlink ? 0 : O_NOFOLLOW);
|
||||
let fd: number;
|
||||
try {
|
||||
fd = fs.openSync(filePath, fs.constants.O_RDONLY | O_NOFOLLOW);
|
||||
fd = fs.openSync(filePath, openFlags);
|
||||
} catch (err) {
|
||||
const code = (err as NodeJS.ErrnoException).code;
|
||||
if (code === 'ENOENT') return null;
|
||||
|
|
|
|||
|
|
@ -177,6 +177,52 @@ describe('Configure AWS Credentials helpers', {}, () => {
|
|||
fs.mkdirSync('/dir/subdir', { recursive: true });
|
||||
expect(() => helpers.readFileUtf8('/dir/subdir')).toThrow(/not a regular file/);
|
||||
});
|
||||
|
||||
it.skipIf(process.platform === 'win32')(
|
||||
'follows the kubelet projected-token symlink chain at /var/run/secrets/*/serviceaccount/token',
|
||||
() => {
|
||||
fs.mkdirSync('/var/run/secrets/eks.amazonaws.com/serviceaccount/..2026_05_28_00_00_00.123', {
|
||||
recursive: true,
|
||||
});
|
||||
fs.writeFileSync(
|
||||
'/var/run/secrets/eks.amazonaws.com/serviceaccount/..2026_05_28_00_00_00.123/token',
|
||||
'jwt-token',
|
||||
);
|
||||
fs.symlinkSync('..2026_05_28_00_00_00.123', '/var/run/secrets/eks.amazonaws.com/serviceaccount/..data');
|
||||
fs.symlinkSync('..data/token', '/var/run/secrets/eks.amazonaws.com/serviceaccount/token');
|
||||
expect(helpers.readFileUtf8('/var/run/secrets/eks.amazonaws.com/serviceaccount/token')).toBe('jwt-token');
|
||||
},
|
||||
);
|
||||
|
||||
it.skipIf(process.platform === 'win32')('still refuses symlinks at lookalike paths outside the allowlist', () => {
|
||||
fs.mkdirSync('/var/run/secrets/eks.amazonaws.com/serviceaccount', { recursive: true });
|
||||
fs.writeFileSync('/var/run/secrets/eks.amazonaws.com/serviceaccount/secret', 'jwt-token');
|
||||
fs.symlinkSync(
|
||||
'/var/run/secrets/eks.amazonaws.com/serviceaccount/secret',
|
||||
'/var/run/secrets/eks.amazonaws.com/serviceaccount/token2',
|
||||
);
|
||||
expect(() => helpers.readFileUtf8('/var/run/secrets/eks.amazonaws.com/serviceaccount/token2')).toThrow(
|
||||
/Refusing .* \(.* symbolic link\)/,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAllowListed', {}, () => {
|
||||
it.skipIf(process.platform === 'win32')('matches the canonical kubelet projected-token path', () => {
|
||||
expect(helpers.isAllowListed('/var/run/secrets/eks.amazonaws.com/serviceaccount/token')).toBe(true);
|
||||
expect(helpers.isAllowListed('/var/run/secrets/kubernetes.io/serviceaccount/token')).toBe(true);
|
||||
});
|
||||
|
||||
it.skipIf(process.platform === 'win32')('rejects nested or unrelated paths', () => {
|
||||
expect(helpers.isAllowListed('/var/run/secrets/serviceaccount/token')).toBe(false);
|
||||
expect(helpers.isAllowListed('/var/run/secrets/a/b/serviceaccount/token')).toBe(false);
|
||||
expect(helpers.isAllowListed('/var/run/secrets/eks.amazonaws.com/serviceaccount/token2')).toBe(false);
|
||||
expect(helpers.isAllowListed('/etc/var/run/secrets/foo/serviceaccount/token')).toBe(false);
|
||||
});
|
||||
|
||||
it.skipIf(process.platform === 'win32')('normalizes path traversal attempts', () => {
|
||||
expect(helpers.isAllowListed('/var/run/secrets/foo/serviceaccount/../../../../etc/passwd')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('writeFileUtf8', {}, () => {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import {
|
|||
AssumeRoleCommand,
|
||||
AssumeRoleWithWebIdentityCommand,
|
||||
GetCallerIdentityCommand,
|
||||
PackedPolicyTooLargeException,
|
||||
STSClient,
|
||||
} from '@aws-sdk/client-sts';
|
||||
import { mockClient } from 'aws-sdk-client-mock';
|
||||
|
|
@ -202,6 +203,18 @@ describe('Configure AWS Credentials', {}, () => {
|
|||
expect(core.setOutput).toHaveBeenCalledTimes(2);
|
||||
expect(core.setFailed).not.toHaveBeenCalled();
|
||||
});
|
||||
it('does not send Tags or TransitiveTagKeys to AssumeRoleWithWebIdentity', async () => {
|
||||
// AssumeRoleWithWebIdentity reads session tags from JWT claims, not the request.
|
||||
// Both fields must be stripped before the STS call.
|
||||
vi.mocked(core.getMultilineInput).mockImplementation((name: string) => {
|
||||
if (name === 'transitive-tag-keys') return ['Repository'];
|
||||
return [];
|
||||
});
|
||||
await run();
|
||||
const callInput = mockedSTSClient.commandCalls(AssumeRoleWithWebIdentityCommand)[0].args[0].input;
|
||||
expect(callInput.Tags).toBeUndefined();
|
||||
expect(callInput.TransitiveTagKeys).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Assume existing role', {}, () => {
|
||||
|
|
@ -282,9 +295,9 @@ describe('Configure AWS Credentials', {}, () => {
|
|||
await run();
|
||||
const tags = mockedSTSClient.commandCalls(AssumeRoleCommand)[0].args[0].input.Tags ?? [];
|
||||
// 7 protected (GitHub + Repository, Workflow, Action, Actor, Commit, Branch)
|
||||
// + 8 overrideable (EventName, BaseRef, HeadRef, RefName, RunId, RefType, Job, TriggeringActor).
|
||||
// No custom-tags, all env vars set in mocks.envs → all 15 should be present, nothing else.
|
||||
expect(tags).toHaveLength(15);
|
||||
// + 6 droppable (EventName, BaseRef, HeadRef, RunId, Job, TriggeringActor).
|
||||
// No custom-tags, all env vars set in mocks.envs → all 13 should be present, nothing else.
|
||||
expect(tags).toHaveLength(13);
|
||||
const tagsByKey = Object.fromEntries(tags.map((t) => [t.Key, t.Value]));
|
||||
expect(tagsByKey).toEqual({
|
||||
GitHub: 'Actions',
|
||||
|
|
@ -297,14 +310,12 @@ describe('Configure AWS Credentials', {}, () => {
|
|||
EventName: 'pull_request',
|
||||
BaseRef: 'main',
|
||||
HeadRef: 'feature-branch',
|
||||
RefName: 'feature-branch',
|
||||
RunId: '16412345678',
|
||||
RefType: 'branch',
|
||||
Job: 'build',
|
||||
TriggeringActor: 'MY-USERNAME_bot_',
|
||||
});
|
||||
});
|
||||
it('omits overrideable tags whose env vars are unset', {}, async () => {
|
||||
it('omits droppable tags whose env vars are unset', {}, async () => {
|
||||
vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.IAM_ASSUMEROLE_INPUTS));
|
||||
delete process.env.GITHUB_BASE_REF;
|
||||
delete process.env.GITHUB_HEAD_REF;
|
||||
|
|
@ -318,6 +329,27 @@ describe('Configure AWS Credentials', {}, () => {
|
|||
expect(tagKeys).toContain('EventName');
|
||||
expect(tagKeys).toContain('RunId');
|
||||
});
|
||||
it('drops droppable tags and retries on PackedPolicyTooLargeException', {}, async () => {
|
||||
vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.IAM_ASSUMEROLE_INPUTS));
|
||||
mockedSTSClient
|
||||
.on(AssumeRoleCommand)
|
||||
.rejectsOnce(new PackedPolicyTooLargeException({ message: 'too large', $metadata: {} }))
|
||||
.resolvesOnce(mocks.outputs.STS_CREDENTIALS);
|
||||
await run();
|
||||
expect(core.info).toHaveBeenCalledWith('Session tag size is too large; dropping droppable tags and retrying.');
|
||||
const retryInput = mockedSTSClient.commandCalls(AssumeRoleCommand)[1].args[0].input;
|
||||
const retryTagKeys = (retryInput.Tags ?? []).map((t) => t.Key);
|
||||
expect(retryTagKeys).not.toContain('EventName');
|
||||
expect(retryTagKeys).not.toContain('BaseRef');
|
||||
expect(retryTagKeys).not.toContain('HeadRef');
|
||||
expect(retryTagKeys).not.toContain('RunId');
|
||||
expect(retryTagKeys).not.toContain('Job');
|
||||
expect(retryTagKeys).not.toContain('TriggeringActor');
|
||||
// Protected tags remain
|
||||
expect(retryTagKeys).toContain('GitHub');
|
||||
expect(retryTagKeys).toContain('Repository');
|
||||
expect(core.setFailed).not.toHaveBeenCalled();
|
||||
});
|
||||
it('sanitizes invalid characters in env-derived tag values', {}, async () => {
|
||||
vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.IAM_ASSUMEROLE_INPUTS));
|
||||
process.env.GITHUB_HEAD_REF = 'feature/has spaces&bad?chars';
|
||||
|
|
@ -370,8 +402,6 @@ describe('Configure AWS Credentials', {}, () => {
|
|||
{ Key: 'EventName', Value: 'pull_request' },
|
||||
{ Key: 'RunId', Value: '16412345678' },
|
||||
{ Key: 'Job', Value: 'build' },
|
||||
{ Key: 'RefName', Value: 'feature-branch' },
|
||||
{ Key: 'RefType', Value: 'branch' },
|
||||
{ Key: 'TriggeringActor', Value: 'MY-USERNAME_bot_' },
|
||||
{ Key: 'Environment', Value: 'Production' },
|
||||
{ Key: 'Team', Value: 'DevOps' },
|
||||
|
|
@ -420,7 +450,7 @@ describe('Configure AWS Credentials', {}, () => {
|
|||
await run();
|
||||
expect(core.warning).toHaveBeenCalledWith(expect.stringContaining("'custom-tags' is set but will be ignored"));
|
||||
});
|
||||
it('lets custom tags override overrideable default tag keys', {}, async () => {
|
||||
it('rejects custom tags that conflict with droppable tag keys', {}, async () => {
|
||||
vi.mocked(core.getInput).mockImplementation(
|
||||
mocks.getInput({
|
||||
...mocks.IAM_ASSUMEROLE_INPUTS,
|
||||
|
|
@ -428,13 +458,10 @@ describe('Configure AWS Credentials', {}, () => {
|
|||
}),
|
||||
);
|
||||
await run();
|
||||
const tags = mockedSTSClient.commandCalls(AssumeRoleCommand)[0].args[0].input.Tags ?? [];
|
||||
const eventNameTags = tags.filter((t) => t.Key === 'EventName');
|
||||
const baseRefTags = tags.filter((t) => t.Key === 'BaseRef');
|
||||
expect(eventNameTags).toHaveLength(1);
|
||||
expect(eventNameTags[0]?.Value).toBe('workflow_dispatch');
|
||||
expect(baseRefTags).toHaveLength(1);
|
||||
expect(baseRefTags[0]?.Value).toBe('release/2026');
|
||||
expect(core.setFailed).toHaveBeenCalledWith(
|
||||
"custom-tags: key 'EventName' conflicts with a protected session tag set by this action and cannot be overridden",
|
||||
);
|
||||
expect(mockedSTSClient.commandCalls(AssumeRoleCommand)).toHaveLength(0);
|
||||
});
|
||||
it('rejects custom tags that conflict with the protected Branch tag', {}, async () => {
|
||||
// Regression guard: Branch was a default before v6.2 and must remain unoverridable.
|
||||
|
|
@ -450,62 +477,10 @@ describe('Configure AWS Credentials', {}, () => {
|
|||
);
|
||||
expect(mockedSTSClient.commandCalls(AssumeRoleCommand)).toHaveLength(0);
|
||||
});
|
||||
it('drops lower-priority overrideable tags when custom-tags would exceed the session-tag limit', {}, async () => {
|
||||
// 7 protected (GitHub + 6 from PROTECTED_TAG_SOURCES) + 40 custom = 47 used → 3 overrideable slots.
|
||||
// The first 3 overrideable tags by priority are EventName, BaseRef, HeadRef (RefName, RunId, RefType,
|
||||
// Job, TriggeringActor must be dropped).
|
||||
it('rejects custom-tags that would exceed the session-tag limit', {}, async () => {
|
||||
// 13 existing tags (7 non-droppable + 6 droppable) + 38 custom = 51 > 50.
|
||||
const customTagsObj: Record<string, string> = {};
|
||||
for (let i = 0; i < 40; i++) {
|
||||
customTagsObj[`Custom${i}`] = `value${i}`;
|
||||
}
|
||||
vi.mocked(core.getInput).mockImplementation(
|
||||
mocks.getInput({
|
||||
...mocks.IAM_ASSUMEROLE_INPUTS,
|
||||
'custom-tags': JSON.stringify(customTagsObj),
|
||||
}),
|
||||
);
|
||||
await run();
|
||||
const tags = mockedSTSClient.commandCalls(AssumeRoleCommand)[0].args[0].input.Tags ?? [];
|
||||
const tagKeys = tags.map((t) => t.Key);
|
||||
expect(tags).toHaveLength(50);
|
||||
expect(tagKeys).toContain('Branch');
|
||||
expect(tagKeys).toContain('EventName');
|
||||
expect(tagKeys).toContain('BaseRef');
|
||||
expect(tagKeys).toContain('HeadRef');
|
||||
expect(tagKeys).not.toContain('RefName');
|
||||
expect(tagKeys).not.toContain('RunId');
|
||||
expect(tagKeys).not.toContain('RefType');
|
||||
expect(tagKeys).not.toContain('Job');
|
||||
expect(tagKeys).not.toContain('TriggeringActor');
|
||||
});
|
||||
it('overridden overrideable tags free a slot for a lower-priority overrideable tag', {}, async () => {
|
||||
// Same 40-custom-tag scenario as above, but one of the customs overrides BaseRef.
|
||||
// BaseRef no longer competes for the overrideable budget, so the next-priority overrideable (RefName) gets in.
|
||||
const customTagsObj: Record<string, string> = { BaseRef: 'release/2026' };
|
||||
for (let i = 0; i < 39; i++) {
|
||||
customTagsObj[`Custom${i}`] = `value${i}`;
|
||||
}
|
||||
vi.mocked(core.getInput).mockImplementation(
|
||||
mocks.getInput({
|
||||
...mocks.IAM_ASSUMEROLE_INPUTS,
|
||||
'custom-tags': JSON.stringify(customTagsObj),
|
||||
}),
|
||||
);
|
||||
await run();
|
||||
const tags = mockedSTSClient.commandCalls(AssumeRoleCommand)[0].args[0].input.Tags ?? [];
|
||||
const tagKeys = tags.map((t) => t.Key);
|
||||
expect(tags).toHaveLength(50);
|
||||
expect(tagKeys).toContain('Branch');
|
||||
expect(tagKeys).toContain('EventName');
|
||||
expect(tagKeys).toContain('BaseRef');
|
||||
expect(tagKeys).toContain('HeadRef');
|
||||
expect(tagKeys).toContain('RefName');
|
||||
expect(tagKeys).not.toContain('RunId');
|
||||
});
|
||||
it('rejects custom-tags that would exceed the session-tag limit on their own', {}, async () => {
|
||||
// 7 protected + 44 custom = 51, which is over 50 even with zero overrideable tags.
|
||||
const customTagsObj: Record<string, string> = {};
|
||||
for (let i = 0; i < 44; i++) {
|
||||
for (let i = 0; i < 38; i++) {
|
||||
customTagsObj[`Custom${i}`] = `value${i}`;
|
||||
}
|
||||
vi.mocked(core.getInput).mockImplementation(
|
||||
|
|
@ -518,12 +493,10 @@ describe('Configure AWS Credentials', {}, () => {
|
|||
expect(core.setFailed).toHaveBeenCalledWith(expect.stringContaining('would exceed the AWS limit of 50'));
|
||||
expect(mockedSTSClient.commandCalls(AssumeRoleCommand)).toHaveLength(0);
|
||||
});
|
||||
it('drops transitive-tag-keys entries that refer to evicted overrideable tags', {}, async () => {
|
||||
// Force eviction of all overrideable tags below EventName/BaseRef/HeadRef. The user transitive-tags
|
||||
// RunId (which gets evicted) and Repository (which is protected and stays). The TransitiveTagKeys
|
||||
// payload must include only the keys that actually appear in Tags.
|
||||
it('allows custom-tags up to the session-tag limit', {}, async () => {
|
||||
// 13 existing tags + 37 custom = 50, exactly at the limit.
|
||||
const customTagsObj: Record<string, string> = {};
|
||||
for (let i = 0; i < 40; i++) {
|
||||
for (let i = 0; i < 37; i++) {
|
||||
customTagsObj[`Custom${i}`] = `value${i}`;
|
||||
}
|
||||
vi.mocked(core.getInput).mockImplementation(
|
||||
|
|
@ -532,15 +505,10 @@ describe('Configure AWS Credentials', {}, () => {
|
|||
'custom-tags': JSON.stringify(customTagsObj),
|
||||
}),
|
||||
);
|
||||
vi.mocked(core.getMultilineInput).mockImplementation((name: string) => {
|
||||
if (name === 'transitive-tag-keys') return ['Repository', 'RunId'];
|
||||
return [];
|
||||
});
|
||||
await run();
|
||||
const callInput = mockedSTSClient.commandCalls(AssumeRoleCommand)[0].args[0].input;
|
||||
const tagKeys = (callInput.Tags ?? []).map((t) => t.Key);
|
||||
expect(tagKeys).not.toContain('RunId');
|
||||
expect(callInput.TransitiveTagKeys).toEqual(['Repository']);
|
||||
expect(core.setFailed).not.toHaveBeenCalled();
|
||||
const tags = mockedSTSClient.commandCalls(AssumeRoleCommand)[0].args[0].input.Tags ?? [];
|
||||
expect(tags).toHaveLength(50);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -105,8 +105,6 @@ const envs = {
|
|||
GITHUB_EVENT_NAME: 'pull_request',
|
||||
GITHUB_RUN_ID: '16412345678',
|
||||
GITHUB_JOB: 'build',
|
||||
GITHUB_REF_NAME: 'feature-branch',
|
||||
GITHUB_REF_TYPE: 'branch',
|
||||
GITHUB_BASE_REF: 'main',
|
||||
GITHUB_HEAD_REF: 'feature-branch',
|
||||
GITHUB_TRIGGERING_ACTOR: 'MY-USERNAME[bot]',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue