Commit Graph

18 Commits

Author SHA1 Message Date
Austin Merrick c7349fbb7a fix(ci): also remove .mcp.json before running Claude Code
Without --bare, claude -p launches MCP servers defined in the project-level
.mcp.json before the model loads. A PR replacing .mcp.json with a malicious
entry gets an attacker-controlled subprocess launched on the CI runner —
same RCE surface as a SessionStart hook.

This repo already has .mcp.json committed (nx-mcp). Removing it before the
social copy generator runs is safe: the workflow's --allowedTools already
restricts Claude to specific read/diff tools and MCP servers are not needed
for social copy generation.

Call-site enumeration: rm -f is self-contained, no callers.
2026-05-21 12:48:56 -07:00
Austin Merrick 90a2c5952f fix(ci): also remove settings.local.json and move cleanup to after checkout
Extends the security fix to also cover .claude/settings.local.json, which
Claude Code reads with equal authority to settings.json. A PR author can
force-commit a gitignored file, so the .gitignore entry does not protect
against this vector.

Also moves the removal step to immediately after Checkout (before any other
step runs in the checked-out workspace), rather than after Install Claude Code.
Claude is not invoked during the intermediate steps, but this ordering is
strictly more defensive and prevents any future step insertions from reopening
the window.

Call-site enumeration: rm -f has no callers; step is self-contained YAML.
2026-05-21 12:44:52 -07:00
Austin Merrick ce51717983 fix(ci): remove untrusted .claude/settings.json before running Claude Code 2026-05-21 12:35:48 -07:00
dependabot[bot] 5799857379 chore(ci)(deps): bump actions/upload-artifact from 4.6.2 to 7.0.1
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.6.2 to 7.0.1.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/ea165f8d65b6e75b540449e92b4886f43607fa02...043fb46d1a93c77aae656e7c1c64a875d1fc6a0a)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-15 16:55:58 +00:00
Alem Tuzlak edf10769ac chore(ci): pin actions to SHA, add zizmor + dependabot, tighten permissions
Comprehensive CI/CD security hardening pass over all 33 workflows.

Action pinning
- Every `uses:` is now pinned to a 40-char commit SHA with a `# vX.Y.Z`
  comment alongside (167 occurrences resolved). Tag-style refs like `@v4`
  are mutable and have been used in past supply-chain attacks (e.g.
  tj-actions/changed-files in March 2025) to repoint widely-used actions
  to malicious commits.
- Removed redundant `version: "10.13.1"` hardcodes from `pnpm/action-setup`
  call sites so the action inherits from package.json `packageManager`
  (one source of truth).

Automated maintenance
- Added `.github/dependabot.yml` for the `github-actions` ecosystem so
  SHA pins stay current. Without this, pins go stale fast and new
  upstream advisories never reach us. Minor/patch bumps are grouped;
  major bumps stay separate so they get a real review.

Static analysis
- Added `.github/zizmor.yml` configuration and
  `.github/workflows/security_zizmor.yml` (blocking on PR, runs on push
  to main, weekly schedule for advisory drift). zizmor catches the
  well-known classes of Actions footguns: template injection from
  untrusted input, dangerous triggers, unpinned uses, excessive token
  scopes, secret exfil patterns.
- All 28 high-severity and 54 medium-severity findings from the baseline
  scan are remediated. Each suppression in zizmor.yml carries a
  per-finding justification comment so future maintainers can audit the
  trust assumption.

Workflow hardening (from zizmor + manual audit)
- Added `persist-credentials: false` to every `actions/checkout` except
  the 7 workflows that legitimately push back to the repo via the
  workflow token (release tagging, auto-formatting, docs-sync, registry
  updates). Each retained credential persistence carries a
  `persist-credentials required: ...` comment explaining the call site.
- Routed every attacker-controllable expansion (`github.head_ref`,
  `github.event.pull_request.head.repo.full_name`, `inputs.*`,
  step outputs) through `env:` and referenced as quoted shell variables.
  Eliminates 17 template-injection vectors in fork-PR-reachable
  workflows.
- Added per-job `permissions:` blocks across 14 workflows; demoted
  broad workflow-level `id-token: write` to the specific Depot-runner
  jobs that need it; narrowed `pull-requests: write` /
  `actions: write` to the jobs that actually call those APIs.

Audit-driven fixes
- `publish-release.yml` build job: dropped `token:` and added
  `persist-credentials: false`. The subsequent `Upload workspace` step
  was packing `.git/config` (with the persisted GITHUB_TOKEN) into a
  1-day-retention artifact downloadable by anyone with `actions:read`.
- `auto_merge_showcases.yml`: team-membership check now authorizes on
  the PR AUTHOR (`pull_request.user.login`), never `context.actor` —
  the actor is whoever triggered the latest event, so a team member
  synchronizing or reopening an outsider's PR would otherwise
  green-light auto-merge of code they didn't author.
- `static_quality.yml`: pinned ruff to a specific version so a
  compromised release can't land on the next PR run with the
  persisted-credentials write token in the format job.
- `showcase_capture-previews.yml`: switched the args-string construction
  to a bash array so a slug or demo value containing whitespace or shell
  metacharacters stays a single argument rather than being re-tokenized
  by the shell.
2026-05-14 18:21:57 +02:00
Alem Tuzlak c8cfb2bbe1 ci: switch from base-action to Claude CLI for social copy generator
Replace anthropics/claude-code-base-action@beta with the Claude Code
CLI (`claude -p` with `--output-format json`). This gives direct
control over the output format — a single JSON object with a `result`
field instead of ambiguous JSONL. The extraction script parses the
JSON, strips preamble, and writes clean markdown to pr-social-copy.md
which is uploaded as the artifact and posted to the PR comment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 16:44:18 +01:00
Alem Tuzlak 4d05bb9bd9 fix(ci): parse JSONL output format for result extraction
The claude-execution-output.json is JSONL (one JSON object per line),
not a single JSON object. JSON.parse() on the whole file silently
failed, producing empty output. Now parses line by line, finding the
"type": "result" entry or falling back to the last assistant message.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 16:18:06 +01:00
Alem Tuzlak 31575b8f72 ci: move hashtags from Twitter to LinkedIn post
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 16:12:41 +01:00
Alem Tuzlak d0318e8723 fix(ci): upload clean markdown artifact, remove blog length limit
- Extract result text and save as pr-social-copy.md (not raw JSON)
- Strip preamble/analysis before first ### header
- Upload the markdown file as the artifact (90-day retention)
- Comment reads from the same markdown file
- Remove character limit from blog post and LinkedIn (only Twitter
  keeps 280 char limit)
- Instruct Claude to skip preamble and start directly with content

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 16:04:19 +01:00
Alem Tuzlak 7cb8eba6f8 fix(ci): block TodoWrite, handle error_during_execution
- Add disallowed_tools to prevent Claude from wasting turns on
  TodoWrite, Edit, Write, and other non-essential tools that cause
  error_during_execution crashes
- Make extract/upload/update steps run with always() so they still
  execute even if Claude's step exits with error_during_execution
- Add JSONL log fallback: if result field is empty, scan assistant
  messages for the generated content (contains ###)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 15:59:33 +01:00
Alem Tuzlak 36be36f789 ci: add artifact download link to generated comment
Add a direct "Download full output" link in the comment footer that
points to the uploaded artifact, alongside the existing workflow run
link.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 15:49:36 +01:00
Alem Tuzlak 1faa662dc3 fix(ci): write diff files inside repo for Claude sandbox access
Claude Code sandboxes file access to the working directory. Files in
/tmp are inaccessible regardless of allowed_tools config. Move diff
files and extracted result to .claude-tmp/ inside the repo.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 15:39:21 +01:00
Alem Tuzlak fdc98c42e2 fix(ci): fix output capture, add Read tool, upload artifact
- Add `Read` to allowed_tools so Claude can read the diff files
- Read Claude output from JSON file instead of step output (fixes
  empty result caused by multiline content breaking GH Actions outputs)
- Upload claude-execution-output.json as a downloadable artifact
- Add link to workflow run in the success comment footer

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 15:37:08 +01:00
Alem Tuzlak b61b8b2313 ci: add workflow run link to generating state comment
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 15:27:05 +01:00
Alem Tuzlak 78b92955a8 ci: skip social copy generator for fork PRs and external users
- Skip posting the initial comment on PRs from forks (job-level guard
  + runtime check for workflow_dispatch)
- Verify the checkbox clicker has write/admin permission before
  running generation (prevents external collaborators from triggering
  Claude API calls)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 15:24:46 +01:00
Alem Tuzlak e64ef5f542 fix(ci): pass anthropic_api_key as input, not env var
The claude-code-base-action expects anthropic_api_key as a `with:`
input parameter, not an `env:` variable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 15:01:30 +01:00
Alem Tuzlak 96d595a660 ci: support workflow_dispatch for existing/merged PRs
Add workflow_dispatch trigger with pr_number input so the social copy
generator can be used on any existing PR (open or merged). Also adds
duplicate comment detection and a GitHub API diff fallback for merged
PRs where the branch may have been deleted.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 14:49:21 +01:00
Alem Tuzlak 365471d357 ci: add social copy generator workflow
Add a GitHub Actions workflow that posts a comment on every new PR with a
checkbox to generate social media copies (Twitter/X, LinkedIn, Blog Post)
using Claude Code. Checking the checkbox triggers Claude to analyze the PR
diff and generate content. After generation, the checkbox resets to
"Regenerate" so users can re-trigger after pushing new changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 14:22:15 +01:00