Skip to content

feat(opencode): add hostname-only HSTS - #47

Merged
xnoto merged 4 commits into
mainfrom
feat/opencode-host-hsts
Oct 5, 2026
Merged

xnoto merged 4 commits into
mainfrom
feat/opencode-host-hsts

Conversation

@xnoto

@xnoto xnoto commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Set Strict-Transport-Security: max-age=86400 only on HTTPS responses for opencode.makeitwork.cloud, using the canonical zone response-header ruleset. No includeSubDomains or preload. Native OpenCode authentication and existing HTTPS redirection remain unchanged; Cloudflare Access is explicitly deferred. No AWX cleanup or workload DNS/tunnel change is authored.

Owner approved the final scope, merge when ready, and explicitly authorized the main workflow to apply one new HSTS ruleset plus ten existing DNS metadata updates, with zero deletions. Driving request: owner-approved transport hardening; no issue.

Type of change

  • Feature / enhancement
  • Infrastructure (OpenTofu root or module)
  • Documentation

Validation

  • Required observed PR test and plan checks passed at 47a13e2fd8690f474e840f6b97172718b5c05eac: run 37245404167
  • Generated or centrally distributed files were regenerated by their owning automation, not hand-edited: CI corrected the README resource table

Sanitized final plan: 1 add, 10 change, 0 destroy. The new resource is cloudflare_ruleset.response_headers; the plan confirms the exact HTTPS-host expression, static one-day value and header operation. The only displayed existing-DNS change is + include_shadow_metadata = false on ten records; there are no proposed DNS-destination, type, TTL, proxy or priority changes.

Those ten updates were separately owner-approved after explaining that this is a provider default/query metadata flag but the provider still calls the DNS update API. No ignore_changes workaround, provider constraint change or hand-edited state.

Discovery-only CI previously passed at d49bfb5 with fewer than 1000 returned rulesets and no returned zone response-header entrypoint. That temporary data source/output was never applied and is removed from the final configuration. It was bounded inventory evidence, not proof of all product permissions. No existing ruleset is imported or overwritten intentionally. A create conflict or authorization failure must be investigated rather than bypassed.

Adversarial and infrastructure-security reviewers inspected the complete final Terraform/README diff and found no Critical/High source finding. Final release-readiness review returned READY with no remaining source/version/pin/generated-copy blocker. The owner explicitly approved merge and automatic main apply of the reviewed scope. No local OpenTofu operations or live functional verification are claimed.

Impact and rollout

Producer: tfroot-cloudflare, changed cf-opencode-hsts.tf and README. Provider constraint stays ~> 5.0. Existing shared-workflows@main / arc-tf test-plan-main-apply contract and images/tfroot-runner hook ownership are unchanged. CI automatically generated the docs-table update and passed its confirmation run.

Merge triggers main test then a fresh production-environment-associated apply, not the PR plan. The owner explicitly authorized that automatic apply because effective environment reviewer protection cannot be queried with the available MCP tools. Authorization is scoped to the reviewed HSTS addition and ten metadata updates; stop on any additional change or failure.

No chart/image publication, GitOps selection/reconciliation, workload restart, credential change, Cloudflare Access change or AWX retirement is involved. Post-apply checks remain distinct: HTTPS UI/API HSTS headers, retained authentication rejection, HTTPS redirect final URL, sibling-header behavior and owner phone login/session continuity.

Rollback: reviewed/apply max-age=0 over HTTPS first, then remove the rule. Removing a header alone does not clear browser HSTS; policies otherwise last up to one day from the last receipt. Preserve HTTPS. Do not modify other rules if the shared phase gains additional owners/rules later.

Safety and secrets

  • Contains no plaintext secrets, decrypted SOPS values, state files, kubeconfigs, tokens, or private endpoints
  • No local OpenTofu init/plan/apply/destroy/import/state operations were run or claimed — plans come from pull-request checks
  • Breaking or irreversible effects are described above with rollback notes

AI-assisted implementation and independent source reviews. Merged and automatic apply attempted with explicit owner authorization; see deployment outcome below.

Deployment outcome — 2026-10-05

Merged as 427b50e9f964c775c5e2bed570d495ff6d2327a5. Main run 37246050127 passed test but apply failed.

  • HSTS ruleset creation was denied by Cloudflare: HTTP403, request is not authorized. The CI credential needs an administrator review of effective Transform Rules authorization; MCP and CI credentials must not be conflated. No credential changes or write probes were performed.
  • All ten DNS metadata updates were attempted. mx_primary, mx_secondary and spf reported completion. Seven other records returned provider-inconsistent-result errors involving the computed modified_on timestamp. The errors do not imply Cloudflare rolled back the API requests. Do not report this as a successful or zero-change apply. No state inspection or repair was performed.
  • Credentialless public checks after failure: OpenCode HTTPS UI200, unauthenticated API401 with native Basic challenge; HTTP probe ends at HTTPS after redirect; HSTS absent on UI/API. Checked sibling responses match the pre-apply baseline. Authenticated phone/session behavior was not tested.

Remaining gates: review CI Transform Rules permissions, diagnose/review the provider timestamp failure, obtain a fresh PR plan for any fix, and get explicit retry/apply authorization. Do not dispatch/rerun automatically or widen MCP privileges as a workaround. HSTS is authored/merged but not deployed or functionally verified.

@github-actions

github-actions Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

OpenTofu Test

OpenTofu test passed.

View the workflow run.

View run output
Terraform validate.......................................................Passed
Terraform validate with tflint...........................................Passed
Checkov..................................................................Passed
Terraform fmt............................................................Passed
Terraform docs...........................................................Passed
Detect hardcoded secrets.................................................Passed
check for case conflicts.................................................Passed
check for merge conflicts................................................Passed
check for broken symlinks............................(no files to check)Skipped
check vcs permalinks.....................................................Passed
detect destroyed symlinks................................................Passed
detect private key.......................................................Passed
fix end of files.........................................................Passed
mixed line ending........................................................Passed
trim trailing whitespace.................................................Passed
don't commit to branch..................................................Skipped
check for added large files..............................................Passed

@xnoto xnoto changed the title feat(opencode): validate provider inventory before host-only HSTS feat(opencode): preflight HSTS inventory (blocked by unrelated DNS drift) Oct 4, 2026
@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

OpenTofu Plan

OpenTofu plan passed.

View the workflow run.

View run output
OpenTofu will perform the following actions:

  # cloudflare_dns_record.cluster_bootstrap["api"] will be updated in-place
  ~ resource "cloudflare_dns_record" "cluster_bootstrap" {
        id                      = "c9747f1b361dda28a4df5ba526e81dba"
      + include_shadow_metadata = false
        name                    = "api.makeitwork.cloud"
        tags                    = []
        # (10 unchanged attributes hidden)
    }

  # cloudflare_dns_record.cluster_bootstrap["k3s"] will be updated in-place
  ~ resource "cloudflare_dns_record" "cluster_bootstrap" {
        id                      = "e28458cbe6e640922c88ac81cd7078b0"
      + include_shadow_metadata = false
        name                    = "k3s.makeitwork.cloud"
        tags                    = []
        # (10 unchanged attributes hidden)
    }

  # cloudflare_dns_record.mx_primary will be updated in-place
  ~ resource "cloudflare_dns_record" "mx_primary" {
        id                      = "8a796f0e0bc6ee7df5b3c12e4bb12c4c"
      + include_shadow_metadata = false
        name                    = "makeitwork.cloud"
        tags                    = []
        # (11 unchanged attributes hidden)
    }

  # cloudflare_dns_record.mx_secondary will be updated in-place
  ~ resource "cloudflare_dns_record" "mx_secondary" {
        id                      = "c863d3d675316853e5875e10ea22389e"
      + include_shadow_metadata = false
        name                    = "makeitwork.cloud"
        tags                    = []
        # (11 unchanged attributes hidden)
    }

  # cloudflare_dns_record.onion will be updated in-place
  ~ resource "cloudflare_dns_record" "onion" {
        id                      = "ad10701842575e949fd47157dbad1ecf"
      + include_shadow_metadata = false
        name                    = "onion.makeitwork.cloud"
        tags                    = []
        # (10 unchanged attributes hidden)
    }

  # cloudflare_dns_record.root will be updated in-place
  ~ resource "cloudflare_dns_record" "root" {
        id                      = "84a87346a5cbe0ece3b7152d4dc73fbb"
      + include_shadow_metadata = false
        name                    = "makeitwork.cloud"
        tags                    = []
        # (10 unchanged attributes hidden)
    }

  # cloudflare_dns_record.spf will be updated in-place
  ~ resource "cloudflare_dns_record" "spf" {
        id                      = "f8ea9d0d0ab047e713a0ad330703fed5"
      + include_shadow_metadata = false
        name                    = "makeitwork.cloud"
        tags                    = []
        # (10 unchanged attributes hidden)
    }

  # cloudflare_dns_record.www will be updated in-place
  ~ resource "cloudflare_dns_record" "www" {
        id                      = "5fd875e1005bcbcfd19f595b51329cf7"
      + include_shadow_metadata = false
        name                    = "www.makeitwork.cloud"
        tags                    = []
        # (10 unchanged attributes hidden)
    }

  # cloudflare_dns_record.xnoto_dev_root will be updated in-place
  ~ resource "cloudflare_dns_record" "xnoto_dev_root" {
        id                      = "3e3f91d53e8e5d47f0c9839ec6963beb"
      + include_shadow_metadata = false
        name                    = "xnoto.dev"
        tags                    = []
        # (10 unchanged attributes hidden)
    }

  # cloudflare_dns_record.xnoto_dev_www will be updated in-place
  ~ resource "cloudflare_dns_record" "xnoto_dev_www" {
        id                      = "7c1b966fdc2b93b084456472564de328"
      + include_shadow_metadata = false
        name                    = "www.xnoto.dev"
        tags                    = []
        # (10 unchanged attributes hidden)
    }

  # cloudflare_ruleset.response_headers will be created
  + resource "cloudflare_ruleset" "response_headers" {
      + description  = "Hostname-scoped response security headers"
      + id           = (known after apply)
      + kind         = "zone"
      + last_updated = (known after apply)
      + name         = "Response header transforms"
      + phase        = "http_response_headers_transform"
      + rules        = [
          + {
              + action            = "rewrite"
              + action_parameters = {
                  + headers = {
                      + "strict-transport-security" = {
                          + operation = "set"
                          + value     = "max-age=86400"
                        },
                    }
                }
              + description       = "One-day HSTS for the OpenCode HTTPS hostname only"
              + enabled           = true
              + expression        = "(http.host eq \"opencode.makeitwork.cloud\" and http.request.scheme eq \"https\")"
              + id                = (known after apply)
              + logging           = (known after apply)
              + ref               = "opencode_hsts"
            },
        ]
      + version      = (known after apply)
      + zone_id      = (sensitive value)
    }

Plan: 1 to add, 10 to change, 0 to destroy.
OpenTofu will perform the following actions:

  # cloudflare_dns_record.cluster_bootstrap["api"] will be updated in-place
  ~ resource "cloudflare_dns_record" "cluster_bootstrap" {
        id                      = "c9747f1b361dda28a4df5ba526e81dba"
      + include_shadow_metadata = false
        name                    = "api.makeitwork.cloud"
        tags                    = []
        # (10 unchanged attributes hidden)
    }

  # cloudflare_dns_record.cluster_bootstrap["k3s"] will be updated in-place
  ~ resource "cloudflare_dns_record" "cluster_bootstrap" {
        id                      = "e28458cbe6e640922c88ac81cd7078b0"
      + include_shadow_metadata = false
        name                    = "k3s.makeitwork.cloud"
        tags                    = []
        # (10 unchanged attributes hidden)
    }

  # cloudflare_dns_record.mx_primary will be updated in-place
  ~ resource "cloudflare_dns_record" "mx_primary" {
        id                      = "8a796f0e0bc6ee7df5b3c12e4bb12c4c"
      + include_shadow_metadata = false
        name                    = "makeitwork.cloud"
        tags                    = []
        # (11 unchanged attributes hidden)
    }

  # cloudflare_dns_record.mx_secondary will be updated in-place
  ~ resource "cloudflare_dns_record" "mx_secondary" {
        id                      = "c863d3d675316853e5875e10ea22389e"
      + include_shadow_metadata = false
        name                    = "makeitwork.cloud"
        tags                    = []
        # (11 unchanged attributes hidden)
    }

  # cloudflare_dns_record.onion will be updated in-place
  ~ resource "cloudflare_dns_record" "onion" {
        id                      = "ad10701842575e949fd47157dbad1ecf"
      + include_shadow_metadata = false
        name                    = "onion.makeitwork.cloud"
        tags                    = []
        # (10 unchanged attributes hidden)
    }

  # cloudflare_dns_record.root will be updated in-place
  ~ resource "cloudflare_dns_record" "root" {
        id                      = "84a87346a5cbe0ece3b7152d4dc73fbb"
      + include_shadow_metadata = false
        name                    = "makeitwork.cloud"
        tags                    = []
        # (10 unchanged attributes hidden)
    }

  # cloudflare_dns_record.spf will be updated in-place
  ~ resource "cloudflare_dns_record" "spf" {
        id                      = "f8ea9d0d0ab047e713a0ad330703fed5"
      + include_shadow_metadata = false
        name                    = "makeitwork.cloud"
        tags                    = []
        # (10 unchanged attributes hidden)
    }

  # cloudflare_dns_record.www will be updated in-place
  ~ resource "cloudflare_dns_record" "www" {
        id                      = "5fd875e1005bcbcfd19f595b51329cf7"
      + include_shadow_metadata = false
        name                    = "www.makeitwork.cloud"
        tags                    = []
        # (10 unchanged attributes hidden)
    }

  # cloudflare_dns_record.xnoto_dev_root will be updated in-place
  ~ resource "cloudflare_dns_record" "xnoto_dev_root" {
        id                      = "3e3f91d53e8e5d47f0c9839ec6963beb"
      + include_shadow_metadata = false
        name                    = "xnoto.dev"
        tags                    = []
        # (10 unchanged attributes hidden)
    }

  # cloudflare_dns_record.xnoto_dev_www will be updated in-place
  ~ resource "cloudflare_dns_record" "xnoto_dev_www" {
        id                      = "7c1b966fdc2b93b084456472564de328"
      + include_shadow_metadata = false
        name                    = "www.xnoto.dev"
        tags                    = []
        # (10 unchanged attributes hidden)
    }

  # cloudflare_ruleset.response_headers will be created
  + resource "cloudflare_ruleset" "response_headers" {
      + description  = "Hostname-scoped response security headers"
      + id           = (known after apply)
      + kind         = "zone"
      + last_updated = (known after apply)
      + name         = "Response header transforms"
      + phase        = "http_response_headers_transform"
      + rules        = [
          + {
              + action            = "rewrite"
              + action_parameters = {
                  + headers = {
                      + "strict-transport-security" = {
                          + operation = "set"
                          + value     = "max-age=86400"
                        },
                    }
                }
              + description       = "One-day HSTS for the OpenCode HTTPS hostname only"
              + enabled           = true
              + expression        = "(http.host eq \"opencode.makeitwork.cloud\" and http.request.scheme eq \"https\")"
              + id                = (known after apply)
              + logging           = (known after apply)
              + ref               = "opencode_hsts"
            },
        ]
      + version      = (known after apply)
      + zone_id      = (sensitive value)
    }

Plan: 1 to add, 10 to change, 0 to destroy.

@xnoto xnoto changed the title feat(opencode): preflight HSTS inventory (blocked by unrelated DNS drift) feat(opencode): add hostname-only HSTS Oct 5, 2026
@xnoto
xnoto marked this pull request as ready for review October 5, 2026 00:04
@xnoto
xnoto requested a review from a team as a code owner October 5, 2026 00:04
@xnoto
xnoto merged commit 427b50e into main Oct 5, 2026
3 checks passed
@xnoto
xnoto deleted the feat/opencode-host-hsts branch October 5, 2026 00:04
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.

1 participant