Repository Governance: Permissions, Tags and Checks
Separate access from approval, trace a release tag to tested code, and use local hooks without mistaking them for server enforcement.
Keys, signatures, and labels solve different problems
A warehouse key controls entry. A supervisorβs signature approves dispatch. A label identifies the shipment. Repository permissions, PR approval, and release tags play those roles. None replaces the others.
Start with groups and least privilege. Readers inspect code; contributors propose changes; maintainers manage selected repository settings; a smaller set administers access. In Azure DevOps, inspect inherited permissions and explicit Deny entries when effective access differs from expectations. In GitHub, consider organization base permissions, team access, repository roles, rulesets, and token scope together.
Do not give a deployment identity broad repository administration merely because it needs to download a release. Conversely, someone being able to read a private repository does not mean they may publish its packages or bypass its merge rules.
Design a traceable release
For a fictional booking service, a release chain might be:
Bug AB#123
-> PR with reviewed fix
-> commit 7f... on the release branch
-> CI run with test and coverage evidence
-> immutable artifact identity
-> tag v1.4.2
-> release and deployment record
The abbreviated commit above is illustrative, not a real release. Store complete identifiers in actual automation. A tag names a Git object; a release adds user-facing information around a tag; a deployment records an environment change.
An annotated tag includes a tag message and metadata:
git log -1 --oneline
git tag -a v0.1.0-learning -m "Sandbox release after passing checks"
git show v0.1.0-learning
Run this only in a disposable repository. Creating a local tag does not publish it. Pushing a tag is a separate action. Use permissions or rulesets to protect release-tag creation and modification as required. Moving a tag after consumers build from it destroys a useful assumption about reproducibility.
Signing a tag helps verify its signer and integrity. It does not prove the code was tested, secure, or deployed. Keep those claims tied to independent evidence.
Make quality evidence reachable
A reviewer needs more than a badge saying βcoverage 83%.β Link the PR to the exact run, test report, and coverage report for that commit. If coverage is only for one component, state that scope. A run from a previous commit can be green while the current PR has never been tested.
Use deep links to the work item or issue rather than copying all its text into a PR. For Azure Boards/GitHub integration, put the AB# reference in a supported location such as the PR description. For GitHub-native work, use the appropriate issue link or closing keyword with the correct repository context.
An AI summary should preserve those links and distinguish βreported coverageβ from βrequired threshold enforced.β The pipeline must actually evaluate its quality rule. Merely uploading a report cannot guarantee a failure blocks merging.
Add a hook for fast local feedback
Git hooks run at lifecycle points such as pre-commit or pre-push. A local pre-commit hook can catch syntax or formatting problems before a developer waits for CI.
This illustrative shell hook assumes the project already defines npm run lint and the hook environment can find Node/npm:
#!/bin/sh
set -eu
npm run lint
Put it in a repository-specific hook setup using your teamβs established mechanism. Do not overwrite an existing hook or change a userβs global hooks configuration. On Windows, Gitβs hook execution uses its shell environment; test the actual setup rather than assuming a PowerShell command pasted into a shell hook will run.
Local hooks are not automatically distributed simply because a repository is cloned. They may also be absent, bypassed, or modified. Keep the corresponding required check in CI. The hook improves feedback speed; server-enforced checks protect the integration boundary.
A local hook runs a coverage check, but contributors can merge changes without that check running. What is the correct design?
Try it: inspect one permission and one release label
Prerequisites: a local disposable Git repository and, optionally, a sandbox hosted repository with permission-viewing access. No Azure resource spend is needed.
- Identify one role that should read but not push. Inspect its effective access in the hosting service.
- Create an annotated learning tag after a passing local test and inspect
git show. - Add a harmless local check using your repositoryβs established hook setup.
- Write down where the equivalent CI result becomes a required merge condition.
Expected observation: the tag identifies a specific revision; permission inspection and CI enforcement are separate evidence. A tag does not execute a test.
Cleanup: delete only the local learning tag with git tag -d v0.1.0-learning, remove your sandbox hook through its setup mechanism, and restore only test permissions you changed. Do not remove published release tags from a shared project.
Decision check: an assistant proposes bypassing a hook
Determine whether the hook found a genuine issue or a local setup problem. A one-off bypass must not silently remove the required CI protection or be described as a passing test.