mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-17 02:15:31 +02:00
ci: least-privilege tokens on the two lanes that execute PR-controlled code
free-tests runs PR code (install lifecycle scripts + the suite) with whatever the repo-default GITHUB_TOKEN grant is, persisted into .git/config by checkout. Now: permissions contents:read, persist-credentials false, pinned by the wiring test. actionlint gets the same treatment plus a digest pin on the third-party Docker Hub image (a tag is repointable with no GitHub-side audit trail, and the image sees the mounted checkout). restore-keys added to both caches so a lockfile bump warms from the previous cache; stale --parallel header wording corrected.
This commit is contained in:
@@ -13,11 +13,20 @@ concurrency:
|
|||||||
group: actionlint-${{ github.head_ref || github.ref_name }}
|
group: actionlint-${{ github.head_ref || github.ref_name }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
# Lint needs nothing from the token; the job runs a third-party image with
|
||||||
|
# the checkout mounted, so keep the grant read-only and out of .git/config.
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
actionlint:
|
actionlint:
|
||||||
runs-on: ubicloud-standard-2
|
runs-on: ubicloud-standard-2
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
# Pull the prebuilt image instead of rhysd/actionlint@v1.7.11 (a Docker
|
# Pull the prebuilt image instead of rhysd/actionlint@v1.7.11 (a Docker
|
||||||
# action that rebuilt from source every run: 16s of a 44s job for 1s of lint).
|
# action that rebuilt from source every run: 16s of a 44s job for 1s of
|
||||||
- run: docker run --rm -v "$PWD:/repo" -w /repo rhysd/actionlint:1.7.11 -color
|
# lint). Pinned by DIGEST: a Docker Hub tag is repointable with no
|
||||||
|
# GitHub-side audit trail, and this image sees the mounted checkout.
|
||||||
|
- run: docker run --rm -v "$PWD:/repo" -w /repo rhysd/actionlint:1.7.11@sha256:6f03470d0152251d7f07f7c4dc019dbe7024c72cd952f839544c7798843efa8f -color
|
||||||
|
|||||||
@@ -3,8 +3,9 @@ name: Free Tests
|
|||||||
# The free suite (~400 files: test/, browse/test/, make-pdf/test/, design/test/)
|
# The free suite (~400 files: test/, browse/test/, make-pdf/test/, design/test/)
|
||||||
# had ZERO Linux CI coverage before this lane — only a curated Windows subset
|
# had ZERO Linux CI coverage before this lane — only a curated Windows subset
|
||||||
# ran anywhere. This job runs the whole thing through the canonical runner
|
# ran anywhere. This job runs the whole thing through the canonical runner
|
||||||
# (scripts/test-free-shards.ts): one `bun test --parallel` invocation with
|
# (scripts/test-free-shards.ts): N concurrent shard processes (serial within
|
||||||
# strict-output classification, so a truncated or summary-less run can never
|
# each, plus a trailing serial tree-mutating shard) with strict-output
|
||||||
|
# classification per shard, so a truncated or summary-less run can never
|
||||||
# report green.
|
# report green.
|
||||||
#
|
#
|
||||||
# Deliberately SECRETLESS: free tests make no API calls, so this lane gets no
|
# Deliberately SECRETLESS: free tests make no API calls, so this lane gets no
|
||||||
@@ -16,9 +17,9 @@ name: Free Tests
|
|||||||
# red, fix or quarantine-with-issue — don't make it advisory; an advisory lane
|
# red, fix or quarantine-with-issue — don't make it advisory; an advisory lane
|
||||||
# is permanent false comfort.
|
# is permanent false comfort.
|
||||||
#
|
#
|
||||||
# Sizing note (decision V3): single --parallel job first. If PR runs show it
|
# Sizing note (decision V3): single job first. If PR runs show it slower than
|
||||||
# slower than the eval matrix wall, switch to a matrix of
|
# the eval matrix wall, switch to a matrix of `--shards N --shard i` jobs
|
||||||
# `--shards N --shard i` jobs (indices are stable, empty shards no-op).
|
# (indices are stable, empty shards no-op).
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
@@ -29,12 +30,20 @@ concurrency:
|
|||||||
group: free-tests-${{ github.head_ref || github.run_id }}
|
group: free-tests-${{ github.head_ref || github.run_id }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
# Least privilege: this job executes PR-controlled code (install lifecycle
|
||||||
|
# scripts + the test suite), so the GITHUB_TOKEN gets read-only contents and
|
||||||
|
# the checkout doesn't persist it into .git/config.
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
free-tests:
|
free-tests:
|
||||||
runs-on: ubicloud-standard-8
|
runs-on: ubicloud-standard-8
|
||||||
timeout-minutes: 20
|
timeout-minutes: 20
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
- uses: oven-sh/setup-bun@v2
|
- uses: oven-sh/setup-bun@v2
|
||||||
with:
|
with:
|
||||||
@@ -44,6 +53,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: ~/.bun/install/cache
|
path: ~/.bun/install/cache
|
||||||
key: linux-bun-${{ hashFiles('bun.lock') }}
|
key: linux-bun-${{ hashFiles('bun.lock') }}
|
||||||
|
# A lockfile bump starts from the previous cache instead of cold.
|
||||||
|
restore-keys: |
|
||||||
|
linux-bun-
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: bun install --frozen-lockfile
|
run: bun install --frozen-lockfile
|
||||||
@@ -52,6 +64,8 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: ~/.cache/ms-playwright
|
path: ~/.cache/ms-playwright
|
||||||
key: linux-playwright-${{ hashFiles('bun.lock') }}
|
key: linux-playwright-${{ hashFiles('bun.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
linux-playwright-
|
||||||
|
|
||||||
# Cache restores browser binaries; install is still required for system
|
# Cache restores browser binaries; install is still required for system
|
||||||
# deps and is a fast no-op for already-present browsers.
|
# deps and is a fast no-op for already-present browsers.
|
||||||
|
|||||||
@@ -53,4 +53,12 @@ describe('free-tests workflow wiring', () => {
|
|||||||
expect(entries.length).toBe(count);
|
expect(entries.length).toBe(count);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('least-privilege token: contents read-only, credentials not persisted', () => {
|
||||||
|
// The job executes PR-controlled code (install lifecycle scripts + the
|
||||||
|
// suite itself). A default-grant GITHUB_TOKEN persisted into .git/config
|
||||||
|
// by checkout would hand that code whatever the repo default allows.
|
||||||
|
expect(source).toMatch(/permissions:\s*\n\s*contents:\s*read/);
|
||||||
|
expect(source).toMatch(/persist-credentials:\s*false/);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user