Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10814e68ae |
@@ -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:
|
workflow_dispatch:
|
||||||
pull_request:
|
pull_request:
|
||||||
push:
|
push:
|
||||||
branches: # Specify your branches here
|
branches:
|
||||||
- main # The 'main' branch
|
- master
|
||||||
- 'releases/*' # The release branches
|
- beta
|
||||||
|
- canary
|
||||||
|
- internal
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
qodana:
|
qodana:
|
||||||
|
|||||||
@@ -3,6 +3,18 @@ name: Tests
|
|||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
push:
|
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:
|
jobs:
|
||||||
php:
|
php:
|
||||||
@@ -336,11 +348,42 @@ jobs:
|
|||||||
if: always()
|
if: always()
|
||||||
run: docker compose -f docker-compose.yml -f .github/docker-compose.ci.yml down -v
|
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:
|
release-manager-gate:
|
||||||
name: Release Manager gate
|
name: Release Manager gate
|
||||||
runs-on: [self-hosted, Linux, X64, pleno, backend]
|
runs-on: [self-hosted, Linux, X64, pleno, backend]
|
||||||
needs: [php, edge-agent, edge-broker, edge-gateway-backend]
|
needs: [required-ci]
|
||||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && needs.required-ci.result == 'success' }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Record Release Manager API gate
|
- name: Record Release Manager API gate
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
Backend API for Copenhagen Truck Wash services.
|
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
|
## Architecture & Stack
|
||||||
- **Edge Proxy:** [Traefik 2.11](https://doc.traefik.io/traefik/) (Handles TLS termination, routing, and rate limiting).
|
- **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).
|
- **Web Server:** [Caddy 2.7](https://caddyserver.com/) (Serves the PHP application via FastCGI).
|
||||||
|
|||||||
Reference in New Issue
Block a user