Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
2 changes: 2 additions & 0 deletions .craft.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
minVersion: 3.11.1
changelog:
policy: auto
preReleaseCommand: bash bin/bump-version.sh
Expand All @@ -12,3 +13,4 @@ targets:
access: public
- name: github
tagPrefix: v
floatingTags: ['v{major}']
Comment thread
sentry-junior[bot] marked this conversation as resolved.
Resolved
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist/action/** linguist-generated=true
6 changes: 6 additions & 0 deletions .github/codeql/codeql-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
name: Warden CodeQL config

# dist/ holds build output, such as the committed ncc bundle in dist/action/.
# CodeQL scans the source that it is built from.
paths-ignore:
- dist/**
55 changes: 55 additions & 0 deletions .github/workflows/action-dist.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Action Bundle

# Rebuilds dist/action on same-repo PRs. When the committed bundle is stale,
# the build job uploads the new bundle as an artifact. This workflow runs PR
# code, so it gets no secrets and a read-only token. commit-action-dist.yml
# runs on workflow_run from the default branch and commits the artifact back.
# Fork PRs can't be pushed to, so the "Check action bundle is committed" step
# in ci.yml stays as the gate there and on every other commit.

permissions:
contents: read

on:
pull_request:
branches: [main]

concurrency:
group: action-dist-${{ github.head_ref }}
cancel-in-progress: true

jobs:
build:
# Dependabot runs get no Actions secrets, so ci.yml is the gate there.
if: >-
github.event.pull_request.head.repo.full_name == github.repository &&
github.actor != 'dependabot[bot]'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
ref: ${{ github.event.pull_request.head.sha }}
persist-credentials: false

- uses: pnpm/action-setup@02f6c237bd2518259fed6c71566509edfb3f2b74 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: '24'
cache: 'pnpm'

- run: pnpm install --frozen-lockfile
- run: pnpm build
- run: pnpm build:action

# A stale bundle is not a failure here; commit-action-dist.yml fixes it.
- name: Check for bundle changes
id: check
continue-on-error: true
run: sh bin/check-action-dist.sh

- if: steps.check.outcome == 'failure'
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: action-dist
path: dist/action/
retention-days: 1
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ jobs:
fail-ci-if-error: true
- run: pnpm build
- run: pnpm build:action
- name: Check action bundle is committed
run: sh bin/check-action-dist.sh
- name: Smoke test action built-in skill resolution
run: |
GITHUB_ACTION_PATH="$PWD" node --input-type=module -e "
Expand Down
43 changes: 43 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: CodeQL

# Advanced setup, so .github/codeql/codeql-config.yml can skip dist/.
# Default setup must be off in the repo settings, or GitHub rejects the
# uploads from this workflow.

on:
pull_request:
branches: [main]
push:
branches: [main]
schedule:
- cron: '27 4 * * 1'

permissions:
contents: read

jobs:
analyze:
name: Analyze (${{ matrix.language }})
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [actions, javascript-typescript, python]
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false

- uses: github/codeql-action/init@33d7b85da1a04171e211befe2c739303b9a4c066 # v4.39.3
with:
languages: ${{ matrix.language }}
build-mode: none
config-file: ./.github/codeql/codeql-config.yml

- uses: github/codeql-action/analyze@33d7b85da1a04171e211befe2c739303b9a4c066 # v4.39.3
with:
category: /language:${{ matrix.language }}
77 changes: 77 additions & 0 deletions .github/workflows/commit-action-dist.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: Commit Action Bundle

# Commits the bundle that action-dist.yml built back to the PR branch.
# workflow_run always runs this file from the default branch, so a PR cannot
# change it to read the release bot key. The PR identity comes from the
# workflow_run payload. The artifact is untrusted data: only regular files
# are copied, and no code from the PR checkout runs.

on:
workflow_run:
workflows: [Action Bundle]
types: [completed]

permissions:
contents: read
actions: read

# Key on the head SHA, not the branch. A late run for an older commit must
# not cancel the push for a newer one. The fast-forward push rejects stale runs.
concurrency:
group: commit-action-dist-${{ github.event.workflow_run.head_sha }}
cancel-in-progress: false

jobs:
commit:
if: >-
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.head_repository.full_name == github.repository &&
github.event.workflow_run.actor.login != 'dependabot[bot]' &&
github.event.workflow_run.head_branch != 'main' &&
!startsWith(github.event.workflow_run.head_branch, 'release/')
runs-on: ubuntu-latest
env:
ARTIFACT_DIR: artifact
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
steps:
# Scripts come from the default branch, not from the PR.
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
path: trusted
persist-credentials: false

# No artifact means the bundle was fresh. Then nothing is downloaded.
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
pattern: action-dist
merge-multiple: true
path: ${{ env.ARTIFACT_DIR }}
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ github.token }}

Check warning on line 51 in .github/workflows/commit-action-dist.yml

View check run for this annotation

@sentry/warden / warden: code-review

download-artifact fails when Action Bundle uploads nothing

When the PR bundle is already fresh, Action Bundle uploads no artifact and this step fails, so the designed no-op path never reaches commit-action-dist.sh.
Comment thread
sentry-warden[bot] marked this conversation as resolved.
Resolved

# The exact commit that was built. If the branch moved since, the push
# is not a fast-forward and fails; the new commit gets its own run.
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
ref: ${{ env.HEAD_SHA }}
path: pr
persist-credentials: false

- name: Commit bundle
id: commit
run: sh trusted/bin/commit-action-dist.sh "$ARTIFACT_DIR" pr

- name: Get auth token
if: steps.commit.outputs.committed == 'true'
id: token
uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1
with:
app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }}
private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }}

- name: Push bundle
if: steps.commit.outputs.committed == 'true'
env:
PUSH_TOKEN: ${{ steps.token.outputs.token }}
run: sh trusted/bin/push-action-dist.sh pr
59 changes: 20 additions & 39 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,31 @@
workflow_dispatch:
inputs:
bump:
description: Version bump type
description: Version bump type (ignored when version is set). auto picks it from the commits; pre cuts a prerelease of that version.
required: true
type: choice
default: minor
default: auto
options:
- minor
- auto
- pre
Comment thread
cursor[bot] marked this conversation as resolved.
Resolved
- patch
- minor
- major
version:
description: Exact version override (for example, 0.53.0)
required: false
type: string
force:
description: Force release (bypass blockers)
required: false
type: boolean
default: false

permissions:
contents: read
# Craft writes AI changelog summaries with the workflow token.
copilot-requests: write

jobs:
release:
runs-on: ubuntu-latest
Expand All @@ -41,45 +52,15 @@
node-version: '24'
cache: 'pnpm'

- name: Calculate version
id: version
env:
BUMP: ${{ inputs.bump }}
run: |
CURRENT=$(node -p "require('./packages/warden/package.json').version")
NEW=$(npx semver -i "$BUMP" $CURRENT)
echo "current=$CURRENT" >> $GITHUB_OUTPUT
echo "new=$NEW" >> $GITHUB_OUTPUT

# Craft uses `git describe --tags` to find the previous version. The
# published action tags point to detached dist/ artifact commits, so the
# previous release must have created a reachable source tag before Craft
# prepares the next changelog.
- name: Verify previous source tag
run: |
VERSION="${{ steps.version.outputs.current }}"
SOURCE_TAG="v${VERSION}-src"

if ! git rev-parse "$SOURCE_TAG^{commit}" >/dev/null 2>&1; then
echo "::error::Missing source tag $SOURCE_TAG. The previous release did not finalize its source tag."
exit 1
fi

DESCRIBED_TAG="$(git describe --tags --abbrev=0)"
DESCRIBED_SHA="$(git rev-parse "$DESCRIBED_TAG^{commit}")"
SOURCE_SHA="$(git rev-parse "$SOURCE_TAG^{commit}")"

if [ "$DESCRIBED_SHA" != "$SOURCE_SHA" ]; then
echo "::error::Expected git describe to resolve to $SOURCE_TAG ($SOURCE_SHA), got $DESCRIBED_TAG ($DESCRIBED_SHA)"
exit 1
fi

echo "Craft previous-release baseline: $DESCRIBED_TAG ($DESCRIBED_SHA)"
- name: Check release baseline
if: inputs.version == ''
run: sh bin/check-release-baseline.sh

- name: Prepare release
uses: getsentry/action-prepare-release@c8e1c2009ab08259029170132c384f03c1064c0e # v1
uses: getsentry/craft@v3
env:
GITHUB_TOKEN: ${{ steps.token.outputs.token }}
with:
version: ${{ steps.version.outputs.new }}
version: ${{ inputs.version || inputs.bump }}
force: ${{ inputs.force }}
llm_api_key: ${{ github.token }}

Check failure on line 66 in .github/workflows/release.yml

View check run for this annotation

@sentry/warden / warden: security-review

Privileged release job uses mutable getsentry/craft@v3 tag

The release job mints a Sentry release-bot app token and hands it to `getsentry/craft@v3`, a floating tag that can be rewritten to run arbitrary code with release/publish authority. Pin `getsentry/craft` to a full commit SHA like the surrounding actions.
Comment thread
sentry-warden[bot] marked this conversation as resolved.
Resolved
84 changes: 0 additions & 84 deletions .github/workflows/update-major-tag.yml

This file was deleted.

9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ node_modules/

# Build output
dist/
# The GitHub Action runs from the committed ncc bundle. CI checks that it is fresh.
!/dist/
/dist/*
!/dist/action/
/dist/action/**
!/dist/action/*.js
!/dist/action/*.wasm
!/dist/action/licenses.txt
!/dist/action/package.json
*.tgz

# IDE
Expand Down
Loading
Loading