Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 16 additions & 0 deletions .github/workflows/npm-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,22 @@ jobs:
scope: "@derek-palmer"
- name: Scope package name for GitHub Packages
run: npm pkg set name="@derek-palmer/codeforerunner"
- name: Verify scoped name and tag/version parity
# Guard against a failed/partial rename or a tag/version mismatch
# shipping a mislabeled scoped package.
run: |
set -e
TAG="${GITHUB_REF#refs/tags/v}"
NAME="$(node -e "process.stdout.write(require('./package.json').name)")"
VERSION="$(node -e "process.stdout.write(require('./package.json').version)")"
if [ "$NAME" != "@derek-palmer/codeforerunner" ]; then
echo "scoped name not applied: got '$NAME'" >&2
exit 1
fi
if [ "$TAG" != "$VERSION" ]; then
echo "tag ($TAG) does not match package.json version ($VERSION)" >&2
exit 1
fi
- name: Publish to GitHub Packages
run: npm publish --access public
env:
Expand Down
27 changes: 27 additions & 0 deletions tests/test_workflows_yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,33 @@ def test_npm_publish_workflow_uses_oidc_trusted_publishing():
assert "NODE_AUTH_TOKEN" not in publish_only


def test_github_packages_publish_job_is_scoped_and_isolated():
wf = WORKFLOWS_DIR / "npm-publish.yml"
doc = yaml.safe_load(wf.read_text())
jobs = doc["jobs"]

gpr = jobs.get("publish-gpr")
assert isinstance(gpr, dict), "missing publish-gpr job"
# Runs after npmjs publish, with only packages:write (token auth, not OIDC).
assert gpr.get("needs") == "publish"
assert gpr.get("permissions", {}).get("packages") == "write"
assert "id-token" not in gpr.get("permissions", {})

gpr_text = yaml.dump(gpr)
# Scoped name mutation and GITHUB_TOKEN auth live in this job.
assert 'name="@derek-palmer/codeforerunner"' in gpr_text
assert "NODE_AUTH_TOKEN" in gpr_text
# Before publish, the job verifies the scoped name took effect and the tag
# matches the package version, so a failed mutation can't ship mislabeled.
assert "@derek-palmer/codeforerunner" in gpr_text
assert "GITHUB_REF" in gpr_text

# The npmjs publish job must not perform the scoped-name mutation — the
# rename must not leak into the public npmjs artifact.
publish_text = yaml.dump(jobs.get("publish"))
assert "@derek-palmer/codeforerunner" not in publish_text


def test_docker_publish_workflow_uses_version_tag_and_ghcr():
wf = WORKFLOWS_DIR / "docker-publish.yml"
doc = yaml.safe_load(wf.read_text())
Expand Down