Skip to content
Closed
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
63 changes: 63 additions & 0 deletions .github/workflows/tag-gate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Tag Gate

on:
push:
tags:
- 'v*'

permissions:
contents: read

jobs:
gate:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0

- name: Setup .NET
uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4
with:
dotnet-version: |
8.0.x
10.0.102

- name: Gate - validate tag format (stable/rc)
shell: bash
run: |
set -euo pipefail
TAG="${GITHUB_REF_NAME}"

STABLE_RE='^v[0-9]+\.[0-9]+\.[0-9]+$'
RC_RE='^v[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$'

if [[ "$TAG" =~ $STABLE_RE ]]; then
echo "OK: stable tag $TAG"
elif [[ "$TAG" =~ $RC_RE ]]; then
echo "OK: rc tag $TAG"
else
echo "FAIL: invalid tag format: $TAG" >&2
exit 1
fi
Comment on lines +27 to +43
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tag validation regex patterns here are more restrictive than the regex in tools/ci/release/derive_tag_outputs.sh (line 6). The derive_tag_outputs.sh script uses ^v([0-9]+)\.([0-9]+)\.([0-9]+)(-([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?$ which allows any alphanumeric prerelease identifiers, while this workflow only accepts v*-rc.* format for RC tags. This means tags like v1.0.0-beta.1 or v1.0.0-alpha would pass the gate step calling derive_tag_outputs.sh but fail the tag format validation step. Consider either aligning the patterns or documenting why they differ.

Copilot uses AI. Check for mistakes.

- name: Gate - derive tag outputs (SSOT)
shell: bash
env:
RELEASE_TAG: ${{ github.ref_name }}
run: bash tools/ci/release/derive_tag_outputs.sh
Comment on lines +45 to +49
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The derive_tag_outputs.sh script writes outputs to GITHUB_OUTPUT (version, tag, assembly_version, file_version), but this step doesn't have an id set, so the outputs cannot be referenced by other steps or jobs. If these outputs are needed elsewhere, add an id to this step. If they're not needed, consider using a simpler validation script that doesn't attempt to write outputs.

Copilot uses AI. Check for mistakes.

- name: Evidence
shell: bash
run: |
set -euo pipefail
mkdir -p artifacts/tag-gate
printf '%s\n' "${GITHUB_REF_NAME}" > artifacts/tag-gate/tag.txt

- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
if: always()
with:
name: tag-gate-evidence
path: artifacts/tag-gate/
if-no-files-found: error
45 changes: 45 additions & 0 deletions docs/governance/002_POLICY_TAGGING_RULESETS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# POLICY: GitHub Tag Rulesets `tags-stable` + `tags-rc`
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file extension should be uppercase .MD to be consistent with other governance policy files in this directory. All other policy files use .MD (e.g., 001_POLICY_CI.MD, 002_POLICY_LABELING.MD, 002_POLICY_NAMING_UNIFIED.MD). According to docs/governance/006_INDEX_CI_RULES.MD line 2, governance tooling globs for *.MD uppercase extensions.

Copilot uses AI. Check for mistakes.

## Scope / Target
Tags are SSOT for publish. Patterns:
- stable: `v*` (exclude `v*-rc.*` if UI supports excludes)
- rc: `v*-rc.*`

## Rulesets (GitHub UI)
Create rulesets at https://github.com/tomtastisch/FileClassifier/settings/rules/new?target=tag

### Ruleset `tags-stable`
- Target: tag refs
- Pattern:
- include: `v*`
- exclude: `v*-rc.*` (only if UI supports excludes; otherwise `tags-rc` is stricter and will match rc tags too)
- Enforcement: Active (fail-closed)
- Bypass: minimal (Admins or small Maintainer team). No broad bot/app bypass unless explicitly required.
- Rules to enable (depending on UI availability):
- Restrict/Prevent deletions
- Restrict/Prevent updates / force pushes / moving tags
- (optional) Restrict creations (only if you want to limit who can create release tags)
- (optional) Require signed commits / signed tags (only if available)
- (later) Require status checks (enable only after tag workflows exist and are stable)

### Ruleset `tags-rc`
- Target: tag refs
- Pattern: `v*-rc.*`
- Enforcement and bypass: same as `tags-stable`
- Rules:
- Restrict/Prevent deletions
- Restrict/Prevent updates / force pushes / moving tags
- (optional) Restrict creations
- (optional) Require signed commits / signed tags
- Require status checks once the rc tag workflow is stable (RC is fail-closed)

## Expected behaviour
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

British English spelling 'behaviour' is used here, but should be 'behavior' to match American English spelling used consistently throughout the codebase (e.g., 'behavior' in docs/governance/002_POLICY_LABELING.MD line 4).

Suggested change
## Expected behaviour
## Expected behavior

Copilot uses AI. Check for mistakes.
- Stable and RC tags can’t be moved or deleted (without bypass).
- Stable and RC tags become the auditable SSOT for releases/publish.
- Publish workflows must depend on the tag gate.

## Ordering / rollout
1. Create rulesets (in evaluate mode only if needed, otherwise active).
2. Add `.github/workflows/tag-gate.yml`.
3. Wire publish pipelines to `needs: tag-gate` or via `workflow_run` on success.
Comment on lines +43 to +44
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the rollout plan in the documentation (line 43-44), publish pipelines should be wired to depend on the tag gate using 'needs: tag-gate' or via 'workflow_run' on success. However, the release.yml workflow still only references 'needs: version-policy' (release.yml:99) and doesn't reference this new tag-gate job. The tag-gate workflow will run independently but won't block the release workflow if it fails.

Copilot uses AI. Check for mistakes.
4. Enable status checks for tags only once the checks exist and are stable.
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This policy document is missing the standard "RoC-Bezug" (Rules of Compliance reference) section that appears in other governance policy documents. See examples in docs/governance/001_POLICY_CI.MD lines 52-57 and docs/governance/002_POLICY_LABELING.MD lines 24-28. This section should reference relevant rule files like artifact_contract.yaml, docs_drift.yaml, and shell_safety.yaml if applicable.

Suggested change
4. Enable status checks for tags only once the checks exist and are stable.
4. Enable status checks for tags only once the checks exist and are stable.
## RoC-Bezug
- `rules/artifact_contract.yaml`
- `rules/docs_drift.yaml`
- `rules/shell_safety.yaml`

Copilot uses AI. Check for mistakes.
Loading