Skip to content

feat(AF-993): gate requires an approved change ticket - #1185

Merged
babltiga merged 4 commits into
mainfrom
feature/AF-993-gate-requires-approved-ticket
Oct 22, 2026
Merged

babltiga merged 4 commits into
mainfrom
feature/AF-993-gate-requires-approved-ticket

Conversation

@babltiga

@babltiga babltiga commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Closes #993 (part of #989).

What

On an environment with change_ticket_required = true, the deployment gate now refuses to release a deployment until a linked change ticket is approved.

  • Fourth conjunct in the pure DefaultDeploymentGateService.releasable(status, frozen, scheduledFor, now, ticketRequired, ticketSatisfied). It is computed from deployment_tickets rows only, never from a channel's config.
    • Satisfied when at least one linked ticket has decision = APPROVED and none has decision = REJECTED.
    • No ticket, only unresolved tickets, or a lookup error all answer not releasable (fail closed).
  • Break-glass requests skip the ticket check, as they already skip the freeze check. The skip is audited: DEPLOYMENT_EXECUTED records change_ticket_bypassed = break_glass. A normal confirmation on a flagged environment records change_ticket_required and change_ticket_key instead.
  • Gate response (additive): change_ticket_required and change_ticket { system, external_key, url, status, resolution, decision }. The ticket shown is the newest rejected one (it is what blocks the gate), else the newest approved one, else the newest. It is omitted when no ticket is linked. CI wrappers that branch on .releasable alone keep working.
  • Missing environment: a request whose environment row is gone is not releasable and logs one WARN line per check (no stack trace).
  • Decision trace (POST /admin/deployment-simulations): a hypothetical request has no ticket, so a flagged environment always simulates as not releasable. The GATE_RELEASABILITY step gains a change_ticket_required detail.
  • CI wrappers (GitHub action, GitLab, Azure): the "waiting" log line now names the ticket key and its decision, or says none linked yet. Each wrapper has a new scenario in the offline harness.
  • Sticky approval (DefaultDeploymentTicketService.updateStatus): once a ticket is stamped APPROVED, a later inbound status that matches neither the approve nor the reject list keeps it APPROVED (and decided_at), so a change moving on after CAB approval (Scheduled → Implement → Closed) doesn't close a gate that opened. Only a reject-list match overrides an approval; an unmapped status still clears a REJECTED stamp. This changes the workflow: map ticket resolution onto a deployment decision #992 writer, raised in review (af-java-reviewer).
  • Release job timing: no code change. A request approved before its ticket flips is announced once on a later tick; a test covers this.

Docs and website

  • docs/04-api-spec.md: gate response, releasable formula, confirm-execution audit metadata, decision-trace details
  • docs/03-data-model.md: DEPLOYMENT_EXECUTED metadata and the V202 flag note
  • docs/05-backend.md: gate section
  • docs/18-deployment-governance.md: §5 (four conjuncts, fail-closed rules, break-glass, "never releases" consequence, decision-stamp caveat), §10 (decision trace), Audit & notifications
  • website/docs/guides/deployment-approval/index.html and website/features/deployment-governance/index.html, with sitemap.xml and JSON-LD dates bumped
  • help-corpus/ regenerated; CLAUDE.md deploygov paragraph updated

No frontend change, so no screenshots. No e2e change: no UI or covered flow changed.

Verification

  • mvn -o verify -Pcoverage: BUILD SUCCESS, 11,408 tests, 0 failures. Spotless and checkstyle clean. ApplicationModulesTest, ApiPackageDependencyTest and MessagesParityTest pass. DefaultDeploymentGateService coverage: 100% lines / 90.6% branches.
  • The deploygov unit and integration tests were re-run after the final review fixes.
  • .github/actions/tests/ harness (deployment-gate, ci-templates incl. shellcheck, query-actions): all pass.
  • Website guard suites: 112 tests pass. Help-corpus regeneration leaves no drift.

Review notes

Four reviewers ran: verifier, cross-cutting, Java, and content. None reported a blocker. Fixed in the second commit:

  • the rejected ticket is now shown first
  • a missing environment logs one WARN line instead of an ERROR with a stack trace
  • the wrappers log the ticket's decision
  • the guide states that the ticketing webhook callback is required
  • smaller doc corrections
  • approved ticket decisions are now sticky (third commit), with unit and persistence-IT coverage; docs/03, docs/08 and docs/18 updated

Still open:

  • af-reviewer: a rejected ticket does not fail the CI job fast. The wrappers now log the decision but still poll until their timeout. Failing fast would change wrapper behaviour, so it was not done here.
  • af-java-reviewer / af-reviewer (nit): the decision trace's DENY for a flagged environment uses the generic "not releasable" message. Only the change_ticket_required detail says why.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Frontend Test Results

    1 files  ±0    341 suites  ±0   12m 0s ⏱️ -56s
2 968 tests ±0  2 968 ✅ ±0  0 💤 ±0  0 ❌ ±0 
2 969 runs  ±0  2 969 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 15a25cd. ± Comparison against base commit 6332106.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Coverage Report for Frontend Coverage (frontend)

Status Category Percentage Covered / Total
🟢 Lines 96.56% (🎯 90%) 4326 / 4480
🟢 Statements 95.31% (🎯 90%) 4778 / 5013
🟢 Functions 94.83% (🎯 90%) 1322 / 1394
🟢 Branches 89.11% (🎯 80%) 3104 / 3483
File CoverageNo changed files found.
Generated in workflow #1597 for commit 15a25cd by the Vitest Coverage Report Action

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Backend Test Results

11 409 tests  +18   11 409 ✅ +18   12m 9s ⏱️ -16s
 1 219 suites ± 0        0 💤 ± 0 
 1 219 files   ± 0        0 ❌ ± 0 

Results for commit 15a25cd. ± Comparison against base commit 6332106.

This pull request removes 1 and adds 19 tests. Note that renamed tests count towards both.
com.bablsoft.accessflow.deploygov.internal.DefaultDeploymentTicketServiceTest ‑ updateStatusWithNullDecisionClearsIt
com.bablsoft.accessflow.deploygov.internal.DefaultDeploymentGateServiceTest ‑ breakGlassSkipsTheTicketConjunct
com.bablsoft.accessflow.deploygov.internal.DefaultDeploymentGateServiceTest ‑ confirmExecutionAuditsTheApprovedTicketKey
com.bablsoft.accessflow.deploygov.internal.DefaultDeploymentGateServiceTest ‑ confirmExecutionAuditsTheBreakGlassTicketBypass
com.bablsoft.accessflow.deploygov.internal.DefaultDeploymentGateServiceTest ‑ confirmExecutionRefusesAFlaggedRequestWithoutAnApprovedTicket
com.bablsoft.accessflow.deploygov.internal.DefaultDeploymentGateServiceTest ‑ gateFailsClosedWhenTheEnvironmentIsGone
com.bablsoft.accessflow.deploygov.internal.DefaultDeploymentGateServiceTest ‑ gateFailsClosedWhenTheTicketLookupThrows
com.bablsoft.accessflow.deploygov.internal.DefaultDeploymentGateServiceTest ‑ gateWithFlagOffReportsNoTicketAndNeverLooksOne
com.bablsoft.accessflow.deploygov.internal.DefaultDeploymentGateServiceTest ‑ gateWithFlagOnAndAnApprovedPlusRejectedTicketIsNotReleasable
com.bablsoft.accessflow.deploygov.internal.DefaultDeploymentGateServiceTest ‑ gateWithFlagOnAndAnApprovedTicketIsReleasableAndSurfacesIt
com.bablsoft.accessflow.deploygov.internal.DefaultDeploymentGateServiceTest ‑ gateWithFlagOnAndNoTicketIsNotReleasable
…

♻️ This comment has been updated with latest results.

@github-actions

Copy link
Copy Markdown
Contributor

Backend Code Coverage

Overall Project 95.16% 🍏
Files changed 100% 🍏

File Coverage
DefaultDeploymentTicketService.java 100% 🍏
DefaultDeploymentGateService.java 100% 🍏
DeploymentGateResponse.java 100% 🍏
DeploymentGateView.java 100% 🍏
DefaultDeploymentSimulationService.java 99.79% 🍏

@babltiga
babltiga merged commit b007a2a into main Oct 22, 2026
35 checks passed
@babltiga
babltiga deleted the feature/AF-993-gate-requires-approved-ticket branch October 22, 2026 11:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

deploygov: gate requires an approved ticket on change_ticket_required environments

1 participant