Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
23e6edb
chore(deps): update pinned GitHub Actions
seonghobae Aug 4, 2026
04846d4
ci: align action-version governance assertion
seonghobae Aug 4, 2026
d356b97
Merge branch 'develop' into dependabot/github_actions/github-actions-…
opencode-agent[bot] Aug 4, 2026
745505d
fix(governance): align updated action versions
github-actions[bot] Aug 4, 2026
3361a02
chore(deps): update pinned GitHub Actions
seonghobae Aug 4, 2026
11f0b82
chore(deps): finalize pinned GitHub Actions update
seonghobae Aug 4, 2026
c2e436a
ci: finalize current GitHub Actions governance fixes
seonghobae Aug 4, 2026
55f4fb2
fix(ci): repair PR 1222 finalizer YAML
seonghobae Aug 5, 2026
88eb068
fix(ci): harden Bandit checkout credentials
seonghobae Aug 6, 2026
fa16774
chore(ci): remove PR-specific governance finalizer
seonghobae Aug 6, 2026
c8ead62
Merge branch 'develop' into dependabot/github_actions/github-actions-…
opencode-agent[bot] Aug 6, 2026
de4f65e
chore(ci): align Bandit action annotations
seonghobae Aug 6, 2026
c113227
fix(ci): harden application checkouts
seonghobae Aug 6, 2026
f0de150
chore(ci): align deploy checkout annotation
seonghobae Aug 6, 2026
8978bfa
fix(ci): harden internal mail checkout
seonghobae Aug 6, 2026
451019f
fix(ci): harden Docker workflow checkouts
seonghobae Aug 6, 2026
d8f599c
Merge branch 'develop' into dependabot/github_actions/github-actions-…
opencode-agent[bot] Aug 6, 2026
84615e0
ci(pr-1222): finalize exact action-pin governance
seonghobae Aug 7, 2026
261422b
chore(ci): remove invalid PR 1222 finalizer
seonghobae Aug 7, 2026
b8931e0
Merge branch 'develop' into dependabot/github_actions/github-actions-…
opencode-agent[bot] Aug 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/app-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ jobs:
egress-policy: audit

- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6

- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: ${{ matrix.python-version }}
cache: pip
Expand Down Expand Up @@ -84,14 +84,14 @@ jobs:
egress-policy: audit

- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6


- name: Install pnpm
run: corepack enable pnpm

- name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
with:
node-version: "24"
cache: pnpm
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/bandit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ jobs:
with:
egress-policy: audit

- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v6
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
Comment thread
seonghobae marked this conversation as resolved.
Resolved

- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.14"

Expand All @@ -38,7 +38,7 @@ jobs:

- name: Upload SARIF file
if: ${{ always() }}
uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4
uses: github/codeql-action/upload-sarif@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4
with:
sarif_file: bandit-results.sarif
category: bandit
2 changes: 1 addition & 1 deletion .github/workflows/dependency-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
egress-policy: audit

- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
egress-policy: audit

- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
with:
persist-credentials: false

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
egress-policy: audit

- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6

- name: Set up QEMU
uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0
Expand Down Expand Up @@ -178,7 +178,7 @@ jobs:
egress-policy: audit

- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6

- name: Read release version
id: version
Expand Down Expand Up @@ -248,7 +248,7 @@ jobs:
} >> "$GITHUB_OUTPUT"

- name: Log in to GHCR
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/mail-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ jobs:
${{ vars.MAIL_SMOKE_ALLOWED_ENDPOINTS }}

- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6

- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
cache: pip
Expand Down
244 changes: 244 additions & 0 deletions .github/workflows/pr-1222-finalize-current.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
name: PR 1222 finalize current GitHub Actions governance

on:
push:
branches:
- dependabot/github_actions/github-actions-f2ccb4ebe5
paths:
- .github/workflows/pr-1222-finalize-current.yml

concurrency:
group: pr-1222-finalize-current
cancel-in-progress: false

permissions:
contents: write
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed

jobs:
finalize:
if: github.actor != 'github-actions[bot]'
runs-on: ubuntu-latest
timeout-minutes: 45
env:
PYTHONWARNINGS: error
DISABLE_BACKGROUND_WORKERS: "1"
steps:
- name: Harden the runner
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
with:
egress-policy: audit

- name: Checkout the exact pull-request branch
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: dependabot/github_actions/github-actions-f2ccb4ebe5
fetch-depth: 0
persist-credentials: true

- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.14"
cache: pip
cache-dependency-path: backend/requirements-hashes.txt

- name: Apply least-privilege action-reference repairs
run: |
python - <<'PY'
from pathlib import Path
from textwrap import dedent

checkout_sha = "3d3c42e5aac5ba805825da76410c181273ba90b1"
replacements = {
Path(".github/workflows/app-ci.yml"): {
f"actions/checkout@{checkout_sha} # v6": f"actions/checkout@{checkout_sha} # v7.0.1",
"actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6": "actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0",
},
Path(".github/workflows/bandit.yml"): {
f"actions/checkout@{checkout_sha} # v6": f"actions/checkout@{checkout_sha} # v7.0.1",
"github/codeql-action/upload-sarif@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4": "github/codeql-action/upload-sarif@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4",
},
Path(".github/workflows/deploy.yml"): {
f"actions/checkout@{checkout_sha} # v6": f"actions/checkout@{checkout_sha} # v7.0.1",
},
Path(".github/workflows/docker-publish.yml"): {
f"actions/checkout@{checkout_sha} # v6": f"actions/checkout@{checkout_sha} # v7.0.1",
},
Path(".github/workflows/mail-smoke.yml"): {
f"actions/checkout@{checkout_sha} # v6": f"actions/checkout@{checkout_sha} # v7.0.1",
},
}

for path, path_replacements in replacements.items():
source = path.read_text(encoding="utf-8")
for old, new in path_replacements.items():
if old not in source:
raise SystemExit(f"Expected action reference is absent from {path}: {old}")
source = source.replace(old, new)
path.write_text(source, encoding="utf-8")

workflow_paths = [
Path(".github/workflows/app-ci.yml"),
Path(".github/workflows/bandit.yml"),
Path(".github/workflows/dependency-review.yml"),
Path(".github/workflows/deploy.yml"),
Path(".github/workflows/docker-publish.yml"),
Path(".github/workflows/mail-smoke.yml"),
]

def disable_checkout_credential_persistence(path: Path) -> None:
"""Set checkout credential persistence to false in one workflow."""
lines = path.read_text(encoding="utf-8").splitlines()
index = 0
while index < len(lines):
line = lines[index]
if f"actions/checkout@{checkout_sha}" not in line:
index += 1
continue

stripped = line.lstrip()
use_indent = len(line) - len(stripped)
with_indent = use_indent + 2 if stripped.startswith("- uses:") else use_indent
block_end = index + 1
while block_end < len(lines):
candidate = lines[block_end]
candidate_stripped = candidate.lstrip()
candidate_indent = len(candidate) - len(candidate_stripped)
if candidate_stripped.startswith("- ") and candidate_indent <= use_indent:
break
block_end += 1

if any(
"persist-credentials: false" in candidate
for candidate in lines[index + 1 : block_end]
):
index = block_end
continue

with_line = next(
(
position
for position in range(index + 1, block_end)
if lines[position].strip() == "with:"
and len(lines[position]) - len(lines[position].lstrip()) == with_indent
),
None,
)
if with_line is None:
lines[index + 1 : index + 1] = [
" " * with_indent + "with:",
" " * (with_indent + 2) + "persist-credentials: false",
]
index += 3
else:
lines[with_line + 1 : with_line + 1] = [
" " * (with_indent + 2) + "persist-credentials: false"
]
index = block_end + 1

path.write_text("\n".join(lines) + "\n", encoding="utf-8")

for workflow_path in workflow_paths:
disable_checkout_credential_persistence(workflow_path)

governance_path = Path("backend/tests/test_release_governance.py")
governance = governance_path.read_text(encoding="utf-8")
marker = (
' assert governed_workflows, "no governed GitHub workflows found"\n\n'
" unpinned_major_refs: list[str] = []\n"
)
if marker not in governance:
raise SystemExit("Could not locate the GitHub Action governance insertion point")
exact_contract = dedent(
'''\
assert governed_workflows, "no governed GitHub workflows found"

expected_action_refs = {
"actions/checkout": (
"3d3c42e5aac5ba805825da76410c181273ba90b1",
"v7.0.1",
),
"actions/setup-python": (
"5fda3b95a4ea91299a34e894583c3862153e4b97",
"v7.0.0",
),
"actions/setup-node": (
"820762786026740c76f36085b0efc47a31fe5020",
"v7.0.0",
),
"github/codeql-action/upload-sarif": (
"f205ea1c3313d32999d8d6a48b4f6530d4437b38",
"v4.37.4",
),
"docker/login-action": (
"dbcb813823bdd20940b903addbd779551569679f",
"v4.6.0",
),
}
governed_source = "\\n".join(
workflow_path.read_text(encoding="utf-8")
for workflow_path in governed_workflows
)
for action_name, (expected_sha, expected_version) in expected_action_refs.items():
expected_reference = f"uses: {action_name}@{expected_sha} # {expected_version}"
assert expected_reference in governed_source, (
f"missing exact governed action reference: {expected_reference}"
)
matching_sha_lines = [
line.strip()
for line in governed_source.splitlines()
if f"uses: {action_name}@{expected_sha}" in line
]
assert matching_sha_lines
assert all(
line.endswith(f"# {expected_version}") for line in matching_sha_lines
), "\\n".join(matching_sha_lines)

obsolete_action_shas = {
"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0",
"ece7cb06caefa5fff74198d8649806c4678c61a1",
"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e",
"99df26d4f13ea111d4ec1a7dddef6063f76b97e9",
"af1e73f918a031802d376d3c8bbc3fe56130a9b0",
}
for obsolete_sha in obsolete_action_shas:
assert f"@{obsolete_sha}" not in governed_source

unpinned_major_refs: list[str] = []
'''
)
governance_path.write_text(
governance.replace(marker, exact_contract, 1),
encoding="utf-8",
)
PY

- name: Install the exact backend dependency closure
run: |
python -m pip install --disable-pip-version-check --require-hashes -r backend/requirements-hashes.txt

- name: Verify the complete backend and workflow contracts
run: |
python -m ruff check backend/tests/test_release_governance.py
cd backend
python -m pytest -q
cd ..
python - <<'PY'
from pathlib import Path
import yaml

for workflow_path in sorted(Path(".github/workflows").glob("*.y*ml")):
yaml.safe_load(workflow_path.read_text(encoding="utf-8"))
PY
go run github.com/rhysd/actionlint/cmd/actionlint@v1.7.7
git diff --check

- name: Commit only verified permanent changes
run: |
rm .github/workflows/pr-1222-finalize-current.yml
git diff --check
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
git add .github/workflows backend/tests/test_release_governance.py
git commit -m "fix(ci): finalize exact action governance"
git push origin HEAD:dependabot/github_actions/github-actions-f2ccb4ebe5
2 changes: 1 addition & 1 deletion backend/tests/test_release_governance.py
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ def test_docker_publish_validates_pr_images_and_publishes_semver_images_only_on_
== 2
)
assert (
"docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0"
"docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0"
Comment thread
seonghobae marked this conversation as resolved.
Resolved
in workflow
)
assert (
Expand Down
Loading