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
82 changes: 82 additions & 0 deletions sentry/github/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# As Decided Sentry

Deterministic code enforcement for engineering decisions.

Sentry checks machine-readable constraints carried by your decision artifacts
against the source changes in a pull request. It supports required and
forbidden patterns, import boundaries, full-tree certification, and SARIF
annotations—without embeddings, network calls, or an LLM judge.

## Use it

```yaml
name: Sentry

on:
pull_request:

permissions:
contents: read
security-events: write

jobs:
sentry:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: asdecided/sentry@v0.26.0
```

By default, Sentry checks added lines against the pull request base and uploads
one SARIF report to GitHub Code Scanning.

Use `full: "true"` to certify the complete repository tree:

```yaml
- uses: asdecided/sentry@v0.26.0
with:
full: "true"
```

## Decision constraints

Add a `Code Constraints` block to an accepted decision:

```yaml
version: 1
eligibility: eligible
reason: "The dependency boundary is deterministic and repository-local."
rules:
- id: domain-has-no-database-driver
kind: forbid_import
path_glob: "src/domain/**/*.rs"
pattern: "^(sqlx|diesel)(::|$)"
message: "Domain code must not import a database driver."
```

Supported rule kinds:

- `forbid_import`
- `forbid_pattern`
- `require_pattern`

Sentry deliberately has no model-judged escape hatch. A decision is either
enforced through a deterministic rule, explicitly ineligible, or visibly
unclassified.

## Inputs

| Input | Default | Purpose |
| --- | --- | --- |
| `path` | `decisions` | Decision corpus directory |
| `repository` | `.` | Source repository root |
| `base` | PR base SHA | Git base revision for diff mode |
| `full` | `false` | Check the complete tree |
| `upload-sarif` | `true` | Upload Code Scanning results |
| `sarif-file` | `asdecided-sentry.sarif` | SARIF output path |
| `asdecided-version` | `0.26.0` | Native release to install |

Authoritative development lives in
[asdecided/ci](https://github.com/asdecided/ci/tree/main/sentry).
51 changes: 25 additions & 26 deletions sentry/github/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ inputs:
asdecided-version:
description: "Verified native asdecided-core release to install."
required: false
default: "0.24.0"
default: "0.26.0"

outputs:
exit-code:
Expand All @@ -55,40 +55,39 @@ runs:
bash "$GITHUB_ACTION_PATH/../../shared/install-native.sh" \
"${{ inputs.asdecided-version }}"

- name: Resolve enforcement mode
shell: bash
env:
INPUT_BASE: ${{ inputs.base }}
INPUT_FULL: ${{ inputs.full }}
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: |
if [ "$INPUT_FULL" = "true" ]; then
echo "SENTRY_MODE=--full" >> "$GITHUB_ENV"
exit 0
fi
BASE="$INPUT_BASE"
if [ -z "$BASE" ]; then
BASE="$PR_BASE_SHA"
fi
if [ -z "$BASE" ]; then
echo "::error::Sentry needs a base revision outside a pull_request event; set the base input or use full=true."
exit 2
fi
echo "SENTRY_MODE=--base $BASE" >> "$GITHUB_ENV"

- name: Run As Decided Sentry
id: sentry
shell: bash
env:
INPUT_BASE: ${{ inputs.base }}
INPUT_FULL: ${{ inputs.full }}
INPUT_PATH: ${{ inputs.path }}
INPUT_REPOSITORY: ${{ inputs.repository }}
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
SARIF_FILE: ${{ inputs.sarif-file }}
run: |
set +e
decided sentry "$INPUT_PATH" \
--repository "$INPUT_REPOSITORY" \
$SENTRY_MODE \
--sarif > "$SARIF_FILE"
if [ "$INPUT_FULL" = "true" ]; then
decided sentry "$INPUT_PATH" \
--repository "$INPUT_REPOSITORY" \
--full \
--sarif > "$SARIF_FILE"
else
BASE="$INPUT_BASE"
if [ -z "$BASE" ]; then
BASE="$PR_BASE_SHA"
fi
if [ -z "$BASE" ]; then
echo "::error::Sentry needs a base revision outside a pull_request event; set the base input or use full=true."
code=2
echo "exit_code=$code" >> "$GITHUB_OUTPUT"
exit 0
fi
decided sentry "$INPUT_PATH" \
--repository "$INPUT_REPOSITORY" \
--base "$BASE" \
--sarif > "$SARIF_FILE"
fi
code=$?
echo "exit_code=$code" >> "$GITHUB_OUTPUT"

Expand Down
5 changes: 5 additions & 0 deletions tests/test_facade_packaging.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,9 @@ def test_packager_emits_root_actions_with_facade_relative_installer(tmp_path):
assert "../../shared/install-native.sh" not in action
assert (output / name / "shared" / "install-native.sh").is_file()
assert "pip install" not in action
sentry = output / "sentry"
assert "Deterministic code enforcement" in (
sentry / "README.md"
).read_text(encoding="utf-8")
assert 'default: "0.26.0"' in (sentry / "action.yml").read_text(encoding="utf-8")
assert not (output / "recordkeeper" / "action.yml").exists()
5 changes: 4 additions & 1 deletion tests/test_sentry_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@ def test_sentry_supports_diff_and_full_tree_modes():
inputs = action()["inputs"]
assert inputs["base"]["default"] == ""
assert inputs["full"]["default"] == "false"
assert inputs["asdecided-version"]["default"] == "0.26.0"
commands = " ".join(step.get("run", "") for step in action()["runs"]["steps"])
assert "--full" in commands
assert "--base" in commands
assert '--base "$BASE"' in commands
assert "$SENTRY_MODE" not in commands
assert "$GITHUB_ENV" not in commands


def test_sentry_uploads_one_sarif_and_resurfaces_exit():
Expand Down