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
69 changes: 69 additions & 0 deletions .fsgg/routine-development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"schema": "fsgg.routine-development-policy/v1",
"status": "active",
"defaultRoute": "routine",
"heavyProcessSelection": {
"trigger": "recorded-explicit-human-instruction",
"namedScopeRequired": true,
"absenceOrAmbiguity": "routine"
},
"heavyProcessNonTriggers": [
"strict-label",
"gs2-registration",
"protected-path",
"policy-change",
"modeled-work",
"protected-operation",
"existing-strict-state"
],
"trustModel": {
"repositoryWriters": "trusted",
"purpose": "prevent accidental mistakes and drift",
"excludedClaim": "adversarial protection from repository writers able to alter Actions workflows"
},
"branchPrefix": "routine/",
"allowedOperations": [
"source-change",
"internal-docs"
],
"protectedOperations": [
"publish",
"deploy",
"credential-change",
"destructive-effect",
"migration-cutover",
"external-contract-acceptance"
],
"sensitivePaths": [
".fsgg/",
".github/",
".agents/skills/work-roadmap/",
".claude/skills/work-roadmap/",
"eng/",
"registry/",
"scripts/",
"src/FS.GG.Coord",
"Directory.Build",
"global.json",
"nuget.config"
],
"requiredChecks": [
"repository-required-status-checks",
"routine-eligibility",
"routine-head-binding"
],
"notRequired": [
"issue",
"claim",
"sdd-artifacts",
"phase-lifecycle-ledger",
"independent-critic",
"feedback-report",
"receipt-cycle",
"metadata-done",
"projection-pr"
],
"safeguardRule": "technical-checks-and-operation-authority-remain-independent-and-fail-closed",
"protectedOperationDisposition": "affected-effect-remains-pending-until-authorized",
"legacyAuthority": "evidence-retained-not-a-route-selector"
}
100 changes: 100 additions & 0 deletions .github/workflows/routine-eligibility.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
name: routine-eligibility

# Reliability boundary: pull_request_target loads this workflow definition from the
# default branch. Candidate bytes are fetched only as Git objects for an exact
# base..head diff; no candidate revision is checked out, sourced, imported, or run.
# Repository writers are trusted: this prevents mistakes and drift, but does not
# claim protection from a writer able to alter Actions workflows or spoof a
# name-based check context.
on:
pull_request_target:
types: [opened, synchronize, reopened, edited]

permissions:
contents: read

jobs:
routine-eligibility:
name: routine-eligibility
if: github.event.pull_request.base.ref == github.event.repository.default_branch
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Evaluate with the PR base's policy and validator
shell: bash
env:
PR_BODY: ${{ github.event.pull_request.body }}
PR_NUMBER: ${{ github.event.pull_request.number }}
BASE_REF: ${{ github.event.pull_request.base.ref }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
HEAD_REF: ${{ github.event.pull_request.head.ref }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
REPOSITORY: ${{ github.repository }}
run: |
set -euo pipefail

test "$BASE_REF" = "$DEFAULT_BRANCH" || {
echo "routine-eligibility: PR target $BASE_REF is not default branch $DEFAULT_BRANCH" >&2
exit 1
}
[[ "$BASE_SHA" =~ ^[0-9a-f]{40}$ ]] || {
echo "routine-eligibility: invalid base SHA" >&2
exit 1
}
[[ "$HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] || {
echo "routine-eligibility: invalid head SHA" >&2
exit 1
}

case "$PR_NUMBER" in
''|*[!0-9]*) echo "routine-eligibility: invalid PR number" >&2; exit 1 ;;
esac

inspect="$RUNNER_TEMP/routine-eligibility-repository"
trusted="$RUNNER_TEMP/routine-eligibility-base"
mkdir -p "$inspect" "$trusted/lib"
git -C "$inspect" init -q
git -C "$inspect" remote add origin "https://github.com/$REPOSITORY.git"
git -C "$inspect" fetch --quiet --no-tags --depth=1 origin \
"+refs/heads/${BASE_REF}:refs/remotes/origin/routine-base" \
"+refs/pull/${PR_NUMBER}/head:refs/remotes/origin/routine-head"

observed_base="$(git -C "$inspect" rev-parse refs/remotes/origin/routine-base)"
observed_head="$(git -C "$inspect" rev-parse refs/remotes/origin/routine-head)"
test "$observed_base" = "$BASE_SHA" || {
echo "routine-eligibility: fetched base $observed_base differs from event base $BASE_SHA" >&2
exit 1
}
test "$observed_head" = "$HEAD_SHA" || {
echo "routine-eligibility: fetched head $observed_head differs from event head $HEAD_SHA" >&2
exit 1
}

case "$HEAD_REF" in
routine/*) ;;
*)
echo "routine-eligibility: not applicable to non-routine branch $HEAD_REF"
exit 0
;;
esac

# Both executable files come from the exact PR base. The candidate can
# replace or delete either path without influencing this invocation.
git -C "$inspect" show "$BASE_SHA:scripts/check-claim-generation.py" > "$trusted/check-claim-generation.py"
git -C "$inspect" show "$BASE_SHA:scripts/lib/gate.py" > "$trusted/lib/gate.py"
git -C "$inspect" show "$BASE_SHA:scripts/check-routine-eligibility-envelope.py" > "$trusted/check-routine-eligibility-envelope.py"
printf '%s' "$PR_BODY" > "$trusted/pr-body.md"

python3 "$trusted/check-routine-eligibility-envelope.py" \
--git-dir "$inspect" \
--repository "$REPOSITORY" \
--default-branch "$DEFAULT_BRANCH" \
--base-ref "$BASE_REF" \
--base-revision refs/remotes/origin/routine-base \
--base-sha "$BASE_SHA" \
--head-ref "$HEAD_REF" \
--head-revision refs/remotes/origin/routine-head \
--head-sha "$HEAD_SHA" \
--body "$trusted/pr-body.md" \
--validator "$trusted/check-claim-generation.py"
Loading
Loading