diff --git a/.github/scripts/supply-chain-policy.test.mjs b/.github/scripts/supply-chain-policy.test.mjs index 695b2b3b80..28cdc86e82 100644 --- a/.github/scripts/supply-chain-policy.test.mjs +++ b/.github/scripts/supply-chain-policy.test.mjs @@ -171,9 +171,9 @@ test('dependency graph generation is immutable, fail closed, and wrapper validat const source = `${prSource}\n${trustedSource}`; const actionReferences = source.match(/gradle\/actions\/dependency-submission@[0-9a-f]{40} # v\d+\.\d+\.\d+/g); - assert.equal(actionReferences?.length, 2); - assert.equal((source.match(/dependency-graph-continue-on-failure:\s*false/g) ?? []).length, 2); - assert.equal((source.match(/validate-wrappers:\s*true/g) ?? []).length, 2); + assert.equal(actionReferences?.length, 3); + assert.equal((source.match(/dependency-graph-continue-on-failure:\s*false/g) ?? []).length, 3); + assert.equal((source.match(/validate-wrappers:\s*true/g) ?? []).length, 3); assert.match(prSource, /dependency-graph:\s*generate-and-upload/); assert.equal(workflowName(prSource), 'Generate PR Dependency Graph'); assert.doesNotMatch(prSource, /^ push:/m); @@ -184,6 +184,32 @@ test('dependency graph generation is immutable, fail closed, and wrapper validat assert.doesNotMatch(trustedSource, /^ paths:/m); }); +test('manual dependency baseline is hard-wired to the checked-out main SHA', async () => { + const source = await readFile( + new URL('../workflows/dependency-submission-trusted.yml', import.meta.url), + 'utf8', + ); + const manualJob = /^ submit-main-baseline:\n[\s\S]+$/m.exec(source)?.[0]; + + assert.match(source, /^ workflow_dispatch:\s*$/m); + assert.doesNotMatch(source, /^ workflow_dispatch:\n inputs:/m); + assert.match( + source, + /github\.event_name == 'workflow_dispatch' && 'refs\/heads\/main' \|\| github\.ref/, + ); + assert.ok(manualJob); + assert.match( + manualJob, + /if:\s*github\.event_name == 'workflow_dispatch' && github\.ref == 'refs\/heads\/develop'/, + ); + assert.match(manualJob, /GITHUB_DEPENDENCY_GRAPH_REF:\s*refs\/heads\/main/); + assert.match(manualJob, /^ ref:\s*refs\/heads\/main$/m); + assert.match(manualJob, /snapshot_sha="\$\(git rev-parse HEAD\)"/); + assert.match(manualJob, /GITHUB_DEPENDENCY_GRAPH_SHA=\$snapshot_sha/); + assert.match(manualJob, /dependency-graph:\s*generate-and-submit/); + assert.doesNotMatch(manualJob, /inputs\./); +}); + test('dependency PR workflows use the same complete server-side path filter', async () => { const submission = await readFile( new URL('../workflows/dependency-submission.yml', import.meta.url), diff --git a/.github/workflows/dependency-submission-trusted.yml b/.github/workflows/dependency-submission-trusted.yml index aff3ff7dbf..48b065a630 100644 --- a/.github/workflows/dependency-submission-trusted.yml +++ b/.github/workflows/dependency-submission-trusted.yml @@ -6,9 +6,10 @@ name: Submit Trusted Branch Dependency Graph on: push: branches: [develop, main] + workflow_dispatch: concurrency: - group: trusted-branch-dependency-submission-${{ github.ref }} + group: trusted-branch-dependency-submission-${{ github.event_name == 'workflow_dispatch' && 'refs/heads/main' || github.ref }} cancel-in-progress: true permissions: @@ -16,6 +17,7 @@ permissions: jobs: submit-trusted-branch: + if: github.event_name == 'push' name: Submit trusted branch dependency graph runs-on: ubuntu-latest permissions: @@ -43,3 +45,44 @@ jobs: dependency-graph: generate-and-submit dependency-graph-continue-on-failure: false validate-wrappers: true + + submit-main-baseline: + if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/develop' + name: Submit main dependency graph baseline + runs-on: ubuntu-latest + permissions: + contents: write + env: + # 임의 입력을 받지 않고 실제 checkout 한 main HEAD 에만 기준선을 귀속한다. + GITHUB_DEPENDENCY_GRAPH_JOB_CORRELATOR: afternote-gradle-dependency-graph + GITHUB_DEPENDENCY_GRAPH_REF: refs/heads/main + steps: + - name: Clone main + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: refs/heads/main + persist-credentials: false + + - name: Bind snapshot to checked-out main SHA + id: main-snapshot + shell: bash + run: | + snapshot_sha="$(git rev-parse HEAD)" + echo "sha=$snapshot_sha" >> "$GITHUB_OUTPUT" + echo "GITHUB_DEPENDENCY_GRAPH_SHA=$snapshot_sha" >> "$GITHUB_ENV" + echo "Submitting refs/heads/main at \`$snapshot_sha\`." >> "$GITHUB_STEP_SUMMARY" + + - name: Set up JDK 21 + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0 + with: + distribution: temurin + java-version: '21' + + - name: Generate and submit main dependency graph baseline + uses: gradle/actions/dependency-submission@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0 + with: + additional-arguments: --no-configuration-cache --stacktrace + cache-provider: basic + dependency-graph: generate-and-submit + dependency-graph-continue-on-failure: false + validate-wrappers: true