package web import ( "bytes" "strings" "testing" "gitea.dooplex.hu/admin/felhom-controller/internal/stacks" ) // R-254 site two — WHAT §7.2 ESTABLISHED, PINNED SO IT CANNOT DRIFT BACK. // // The deploy page has TWO places a generated secret can appear, and they are NOT the same question: // // - the PRE-DEPLOY hidden input — a form must carry what it submits. README §318 documents why: // the customer is shown the generated secrets so they can note them down, and submitting them // back is what makes the saved value the SAME one they saw ("no silent re-generation on submit"). // This is NOT the defect and is deliberately left alone. // - the READONLY display input on an ALREADY-DEPLOYED app — nothing is being submitted there (the // hidden input is correctly omitted), yet the value was rendered into the body of a page the // customer merely opens. That IS R-249's shape, and it is what v0.208.0 fixes. // // Both directions are asserted, because "fixed" here means one branch changed and the other did not. const testDeploySecret = "TESTONLY-generated-db-pw-Xy91" func renderDeployPage(t *testing.T, alreadyDeployed bool) string { t.Helper() s := securityHarness(t) s.loadTemplates() data := map[string]interface{}{ "Page": "stacks", "Title": "Telepítés", "Domain": "example.hu", "Stack": stacks.Stack{Name: "vaultwarden", Deployed: alreadyDeployed}, "Meta": stacks.Metadata{DisplayName: "Vaultwarden", Slug: "vaultwarden"}, "AlreadyDeployed": alreadyDeployed, "AutoFields": []stacks.DeployField{ {EnvVar: "DB_PASSWORD", Label: "Adatbázis jelszó", Type: "secret"}, }, "AutoFieldValues": map[string]string{"DB_PASSWORD": testDeploySecret}, } var buf bytes.Buffer if err := s.tmpl.ExecuteTemplate(&buf, "deploy", data); err != nil { t.Fatalf("render deploy: %v", err) } return buf.String() } // RED-PROOF: drop the `{{if $isDeployed}}` branch so the deployed page renders `value="{{$val}}"` // again — this fails, showing the secret returning to the body of a page with nothing to submit. func TestDeployPage_DeployedApp_DoesNotCarryTheSecret(t *testing.T) { html := renderDeployPage(t, true) if strings.Contains(html, testDeploySecret) { t.Error("R-254 site two: an already-deployed app's generated secret is in the response body " + "of its settings page — nothing there submits it, so there is no form reason for it to " + "be in the page at all") } // Assert the CONTROL, not the URL: the revealAutoField() function ships in the page script on // both variants, so a substring match on the endpoint path matches the script and would report a // control that is not there. (This test caught exactly that on itself.) if !strings.Contains(html, `onclick="revealAutoField('vaultwarden','DB_PASSWORD'`) { t.Error("no reveal control rendered, so the customer cannot see their own generated secret") } // The hidden input must NOT appear on a deployed app — it never did, and that is the asymmetry // that makes the readonly input indefensible there. if strings.Contains(html, ``) { t.Error("the pre-deploy form no longer submits the generated secret — the saved value would " + "then not be the one the customer was shown (README §318, 'no silent re-generation on submit')") } if strings.Contains(html, `onclick="revealAutoField(`) { t.Error("the deployed-app reveal control leaked onto the pre-deploy form, where the value is " + "already legitimately present") } }