Skip to content

feat: add GET-only provider-gap drift verification - #103

Open
NWarila wants to merge 2 commits into
mainfrom
feat/provider-gaps
Open

NWarila wants to merge 2 commits into
mainfrom
feat/provider-gaps

Conversation

@NWarila

@NWarila NWarila commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This PR adds declaration-only provider-gap support for fork-PR contributor approval. Repository declarations are normalized and validated in terraform/locals.tf; the planned desired-state projection is emitted without adding a Terraform resource for the provider gap. A GET-only verifier classifies the projected organization and repository targets, and the reusable workflow folds those results into the existing sanitized drift summary, issue lifecycle, and explicit final gate.

The merged F3 inline summary and reporter projection code was deleted from the workflow and reimplemented as the summary and report subcommands of tools/verify_provider_gaps.py. This keeps the two public projections on one closed result validator and one private-resource redaction boundary.

At reviewed head 4e762f7f8a2666817233a893dcda2260ac00a5e4, the reusable-workflow numstat against F3 base 73b86e869fe4e1c61dd1e83ebc52d6adbc50f33f was explicitly +45/-365. At final head 73b96de9d1656097c5ee7a5f7be869355c6b58b6, it is +54/-367.

Structural move and semantic deltas

The renderer move intentionally changes these operational boundaries:

  • workflow booleans are parsed strictly as true or false;
  • the all-mode summary loads the shipped tool, plan.json, and the desired-state projection, and requires the plan members needed to build the redaction union;
  • malformed inputs and an unsafe private-redaction set fail closed before any Terraform address is emitted;
  • a summary failure prevents the later Terraform apply step because apply is not an always() step;
  • a missing plan, desired-state projection, or result document stops the reporter before any issue lookup, edit, comment, or close instead of treating the input as a clean set;
  • the reporter uses its required always() && detector predicate so it can report verifier or summary failures while the final gate independently requires explicit verifier status zero.

v7 fix delta

  • D1: added distinct private repository-name and Terraform instance-key fixtures in both Python suites. Prior state, planned values, change-before, and change-after are covered independently; exact redaction sets and every summary/report surface are asserted. Both name-only and key-only redaction mutants fail.
  • D2: restored the twelve merged F3 inventory-boundary assertions. Organization detector runs retain the three-plane all-clear and recovery wording; personal detector runs use the exact Terraform/provider-gap wording and never publish an inventory claim.
  • D3: added one wall-clock SIGALRM deadline around connect, send, header parsing, and complete body reading while retaining socket timeouts and no retry. Trickle-header and trickle-body peers are bounded, and the prior handler is restored.
  • D4: tests now extract and execute the exact shipped desired-state extraction and verifier wrapper blocks. Exact JSON extraction, failure without a final file, and captured statuses 0/1/2 are asserted.
  • D5: tests independently pin the private-422 contract string, API-version header value, both redaction placeholders, and the 30-second production deadline.
  • D6: each missing detector input is tested independently; summary and report fail, no all-clear is printed, and an existing issue is untouched.
  • D7: producer and consumer now share the closed 100–599 non-boolean status domain, reserve 200 and 422 for their defined branches, reject impossible HTTP reasons, and enforce document-wide credential consistency. Full status-range tables, invalid direct rows, raw 600/999 peers, and mixed-result documents are covered.
  • D8: apply-safety assertions locate Terraform apply and Guard repository destroys by name, and the organization plan-only fixture again covers plan_only=true with detector mode false.
  • D9: coverage totals were recounted from the final tree, the recount command is recorded, and the drift_issue input now describes the Terraform, inventory, and provider-gap union.

Captured acceptance evidence

Head, parent, commit count, clean worktree, and workflow numstats:

reviewed_head=4e762f7f8a2666817233a893dcda2260ac00a5e4
45	365	.github/workflows/reusable-terraform-deploy.yaml
final_head=73b96de9d1656097c5ee7a5f7be869355c6b58b6
54	367	.github/workflows/reusable-terraform-deploy.yaml
commit_count=1
parent=4e762f7f8a2666817233a893dcda2260ac00a5e4
worktree_status_begin
worktree_status_end

Local acceptance at the pinned toolchain:

Terraform v1.15.4
on linux_amd64
Success! 105 passed, 0 failed.
Ran 38 tests in 24.910s
Ran 30 tests in 3.792s
OK (skipped=1)
docs/reference/terraform.md is up to date
docs layout check passed
no OPA policies to test
Ran 12 tests in 0.317s
make_ci_status=0

Each prescribed mutation was applied alone in a scratch copy; mutant=1 is red and reverted=0 is green:

D1-name-unit mutant=1 reverted=0
D1-name-workflow mutant=1 reverted=0
D1-key-unit mutant=1 reverted=0
D1-key-workflow mutant=1 reverted=0
D2-inventory-line mutant=1 reverted=0
D2-organization-summary mutant=1 reverted=0
D2-organization-recovery mutant=1 reverted=0
D3-wall-clock-timer mutant=1 reverted=0
D4-wrapper-capture mutant=1 reverted=0
D5-private-422 mutant=1 reverted=0
D5-api-version mutant=1 reverted=0
D5-private-target mutant=1 reverted=0
D5-private-resource mutant=1 reverted=0
D5-timeout mutant=1 reverted=0

No new repository path was added; the modified tracked paths remain outside the deny-all ignore, no tracked file is ignored, and the committed diff is clean:

new_path_count=0
check_ignore_output_bytes=0
check_ignore_status=1
cached_ignored_output_bytes=0
diff_check_status=0

Hosted checks at the final head all completed successfully except the configured OpenSSF skip:

CodeQL	pass	3s
CodeQL / CodeQL (actions)	pass	47s
IaC and secret scan / Gitleaks (secret scan)	pass	9s
IaC and secret scan / Trivy (filesystem & secrets)	pass	19s
IaC and secret scan / zizmor (Actions security)	pass	13s
Trivy	pass	2s
Validate & Test	pass	1m2s
org-adr / verify	pass	0
org-baseline / verify	pass	8s
org-baseline / verify	pass	0
template-drift / template drift	pass	13s
zizmor	pass	2s
OpenSSF Scorecard	skipping	0

The hosted Terraform Framework Tests / Validate & Test log shows the final counts and the new regression cases executing:

Validate & Test	Terraform Test (Human)	2026-09-15T22:20:27.6389923Z Success! 105 passed, 0 failed.
Validate & Test	Detector Reporter Tests	2026-09-15T22:20:31.6359944Z test_distinct_private_instance_key_is_redacted_from_all_workflow_surfaces (__main__.ReporterTests.test_distinct_private_instance_key_is_redacted_from_all_workflow_surfaces) ... ok
Validate & Test	Detector Reporter Tests	2026-09-15T22:20:32.0402889Z test_each_missing_detector_input_stops_before_issue_lifecycle (__main__.ReporterTests.test_each_missing_detector_input_stops_before_issue_lifecycle) ... ok
Validate & Test	Detector Reporter Tests	2026-09-15T22:20:39.9290727Z test_personal_clean_recovery_closes_with_exact_two_plane_comment (__main__.ReporterTests.test_personal_clean_recovery_closes_with_exact_two_plane_comment) ... ok
Validate & Test	Detector Reporter Tests	2026-09-15T22:20:40.0840441Z test_personal_detector_clean_summary_has_exact_two_plane_all_clear (__main__.ReporterTests.test_personal_detector_clean_summary_has_exact_two_plane_all_clear) ... ok
Validate & Test	Detector Reporter Tests	2026-09-15T22:20:41.4022003Z test_provider_gap_workflow_wrapper_and_cleanup_are_closed (__main__.ReporterTests.test_provider_gap_workflow_wrapper_and_cleanup_are_closed) ... ok
Validate & Test	Detector Reporter Tests	2026-09-15T22:20:44.2967759Z Ran 38 tests in 16.461s
Validate & Test	Provider Gap Tests	2026-09-15T22:20:44.4072201Z test_every_valid_http_status_obeys_the_closed_classifier_contract (__main__.DeclarationAndClassifierTests.test_every_valid_http_status_obeys_the_closed_classifier_contract) ... ok
Validate & Test	Provider Gap Tests	2026-09-15T22:20:44.4132175Z test_distinct_private_instance_key_is_redacted_from_every_rendered_surface (__main__.ReporterProjectionTests.test_distinct_private_instance_key_is_redacted_from_every_rendered_surface) ... ok
Validate & Test	Provider Gap Tests	2026-09-15T22:20:48.0969822Z test_trickled_headers_and_body_share_one_wall_clock_deadline (__main__.ShippedHttpClientTests.test_trickled_headers_and_body_share_one_wall_clock_deadline) ... ok
Validate & Test	Provider Gap Tests	2026-09-15T22:20:48.0971081Z Ran 30 tests in 3.708s
Validate & Test	Provider Gap Tests	2026-09-15T22:20:48.0971317Z OK (skipped=1)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant