Prepare API default branch protection
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
# Default branch protection
|
||||
|
||||
`master` is changed through pull requests. Do not push or publish directly to
|
||||
the default branch, including through automation or the Git Data API.
|
||||
|
||||
## Normal publishing flow
|
||||
|
||||
1. Create a scoped `agent/*` or feature branch from the current `origin/master`.
|
||||
2. Commit and push only the intended changes.
|
||||
3. Open a pull request targeting `master`.
|
||||
4. Wait for the `Required CI` check. If `master` moves, update the branch and
|
||||
wait for the strict check to rerun.
|
||||
5. Resolve every review conversation and squash-merge the pull request.
|
||||
6. Confirm the post-merge `Release Manager gate` completes on `master`.
|
||||
|
||||
The aggregate check covers the PHP unit, integration, API, and legacy matrix,
|
||||
plus Edge Agent, Edge Broker, and Edge Gateway Backend. Qodana is advisory and
|
||||
the Release Manager gate is intentionally post-merge.
|
||||
|
||||
## Desired ruleset
|
||||
|
||||
[`rulesets/protect-default-branch.json`](rulesets/protect-default-branch.json)
|
||||
is the importable final desired-state repository-ruleset request body. For the
|
||||
initial POST, copy the file and override `enforcement` to `disabled`. Inspect
|
||||
the normalized ruleset and verify a green preparation PR and post-merge run,
|
||||
then PUT the exact committed file to activate it.
|
||||
|
||||
The desired rule targets `~DEFAULT_BRANCH`, requires pull requests with zero
|
||||
approvals, conversation resolution, strict `Required CI` from GitHub Actions
|
||||
integration `15368`, squash-only linear history, and blocks deletion and force
|
||||
pushes. Repository administrators receive pull-request-only bypass; they do not
|
||||
receive a standing direct-push bypass.
|
||||
|
||||
When the ruleset is activated, align repository settings at the same time:
|
||||
retain squash merging, disable merge commits and rebase merging, enable
|
||||
auto-merge and branch-update suggestions, delete merged branches automatically,
|
||||
keep the Actions token read-only, and prevent Actions from approving reviews.
|
||||
|
||||
## Break glass
|
||||
|
||||
When an incident cannot wait for the normal gate:
|
||||
|
||||
1. Open a pull request and describe the incident, risk, and reason for bypass.
|
||||
2. Have a repository administrator use the pull-request-only bypass.
|
||||
3. Monitor `Required CI` and the post-merge Release Manager workflow.
|
||||
4. Open a follow-up pull request for any deferred validation or remediation.
|
||||
|
||||
Never bypass by updating `refs/heads/master` directly. Ruleset changes and
|
||||
emergency bypasses must remain visible in GitHub's audit trail.
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"name": "Protect default branch",
|
||||
"target": "branch",
|
||||
"enforcement": "active",
|
||||
"bypass_actors": [
|
||||
{
|
||||
"actor_id": 5,
|
||||
"actor_type": "RepositoryRole",
|
||||
"bypass_mode": "pull_request"
|
||||
}
|
||||
],
|
||||
"conditions": {
|
||||
"ref_name": {
|
||||
"exclude": [],
|
||||
"include": [
|
||||
"~DEFAULT_BRANCH"
|
||||
]
|
||||
}
|
||||
},
|
||||
"rules": [
|
||||
{
|
||||
"type": "deletion"
|
||||
},
|
||||
{
|
||||
"type": "non_fast_forward"
|
||||
},
|
||||
{
|
||||
"type": "required_linear_history"
|
||||
},
|
||||
{
|
||||
"type": "pull_request",
|
||||
"parameters": {
|
||||
"allowed_merge_methods": [
|
||||
"squash"
|
||||
],
|
||||
"dismiss_stale_reviews_on_push": false,
|
||||
"require_code_owner_review": false,
|
||||
"require_last_push_approval": false,
|
||||
"required_approving_review_count": 0,
|
||||
"required_review_thread_resolution": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "required_status_checks",
|
||||
"parameters": {
|
||||
"do_not_enforce_on_create": false,
|
||||
"required_status_checks": [
|
||||
{
|
||||
"context": "Required CI",
|
||||
"integration_id": 15368
|
||||
}
|
||||
],
|
||||
"strict_required_status_checks_policy": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -3,9 +3,11 @@ on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches: # Specify your branches here
|
||||
- main # The 'main' branch
|
||||
- 'releases/*' # The release branches
|
||||
branches:
|
||||
- master
|
||||
- beta
|
||||
- canary
|
||||
- internal
|
||||
|
||||
jobs:
|
||||
qodana:
|
||||
|
||||
@@ -3,6 +3,18 @@ name: Tests
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- beta
|
||||
- canary
|
||||
- internal
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
jobs:
|
||||
php:
|
||||
@@ -336,11 +348,42 @@ jobs:
|
||||
if: always()
|
||||
run: docker compose -f docker-compose.yml -f .github/docker-compose.ci.yml down -v
|
||||
|
||||
required-ci:
|
||||
name: Required CI
|
||||
runs-on: ubuntu-latest
|
||||
needs: [php, edge-agent, edge-broker, edge-gateway-backend]
|
||||
if: ${{ always() }}
|
||||
|
||||
steps:
|
||||
- name: Verify required jobs succeeded
|
||||
env:
|
||||
PHP_RESULT: ${{ needs.php.result }}
|
||||
EDGE_AGENT_RESULT: ${{ needs.edge-agent.result }}
|
||||
EDGE_BROKER_RESULT: ${{ needs.edge-broker.result }}
|
||||
EDGE_GATEWAY_BACKEND_RESULT: ${{ needs.edge-gateway-backend.result }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
failed=0
|
||||
for dependency in \
|
||||
"php=${PHP_RESULT}" \
|
||||
"edge-agent=${EDGE_AGENT_RESULT}" \
|
||||
"edge-broker=${EDGE_BROKER_RESULT}" \
|
||||
"edge-gateway-backend=${EDGE_GATEWAY_BACKEND_RESULT}"
|
||||
do
|
||||
name="${dependency%%=*}"
|
||||
result="${dependency#*=}"
|
||||
if [ "$result" != "success" ]; then
|
||||
echo "Required dependency ${name} completed with result: ${result:-missing}" >&2
|
||||
failed=1
|
||||
fi
|
||||
done
|
||||
test "$failed" -eq 0
|
||||
|
||||
release-manager-gate:
|
||||
name: Release Manager gate
|
||||
runs-on: [self-hosted, Linux, X64, pleno, backend]
|
||||
needs: [php, edge-agent, edge-broker, edge-gateway-backend]
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
needs: [required-ci]
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && needs.required-ci.result == 'success' }}
|
||||
|
||||
steps:
|
||||
- name: Record Release Manager API gate
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
Backend API for Copenhagen Truck Wash services.
|
||||
|
||||
Changes are published from a scoped feature branch through a pull request to
|
||||
`master`; direct default-branch pushes are not part of the release workflow.
|
||||
See [default branch protection](.github/BRANCH_PROTECTION.md) for the CI gate
|
||||
and emergency procedure.
|
||||
|
||||
## Architecture & Stack
|
||||
- **Edge Proxy:** [Traefik 2.11](https://doc.traefik.io/traefik/) (Handles TLS termination, routing, and rate limiting).
|
||||
- **Web Server:** [Caddy 2.7](https://caddyserver.com/) (Serves the PHP application via FastCGI).
|
||||
|
||||
Reference in New Issue
Block a user