From 4ac13f1b77fa916177b895b847ea1ad428e504f8 Mon Sep 17 00:00:00 2001 From: "boatstack-automation[bot]" Date: Sat, 18 Jul 2026 15:10:02 +0000 Subject: [PATCH] Sync Boatstack from Intelligence Flow Labs @ ef0d18195ef8 --- CONTRIBUTING.md | 2 +- UPSTREAM.json | 15 ++++---- boatstack/safety.go | 6 +++- boatstack/safety_test.go | 36 +++++++++++++++++++ docs/evidence-engineered-coding.md | 2 +- docs/public-claims.json | 24 ++++++------- labs/diagram-json/plan.lock.json | 2 +- .../2026-07-18-safety-sql-boundaries.md | 3 ++ 8 files changed, 67 insertions(+), 23 deletions(-) create mode 100644 release-notes/2026-07-18-safety-sql-boundaries.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ac9dd57..27b82c2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ # Contributing -Boatstack is a generated content distribution. Propose changes to workflow semantics, templates, evidence rules, or generated presentation in [Intelligence Flow](https://github.com/operatorstack/intelligence-flow/tree/936457567063d878f7bda40e3a828568c4210e56/labs/12-product-engineering-loop). +Boatstack is a generated content distribution. Propose changes to workflow semantics, templates, evidence rules, or generated presentation in [Intelligence Flow](https://github.com/operatorstack/intelligence-flow/tree/ef0d18195ef87f96891ea35c96866c456c855b1d/labs/12-product-engineering-loop). The Boatstack repository receives product/runtime changes through a generated pull request. Review the PR's `UPSTREAM.json`, tests, adapter diff, and context-size change; do not hand-edit generated output on `main`. `.github/workflows` is the exception: it is Boatstack's executable control plane, excluded from scheduled projection and changed only through a separate manually reviewed Boatstack PR. diff --git a/UPSTREAM.json b/UPSTREAM.json index 5ee6f5d..30434a2 100644 --- a/UPSTREAM.json +++ b/UPSTREAM.json @@ -12,7 +12,7 @@ }, "files": { ".gitignore": "a7079e923a776f14f1bb3a6aa0a11a133a8e1dfb35af020f327623357b7e3957", - "CONTRIBUTING.md": "dfa63ceca996d539e5fca77e9b26d376750d9c94824b1900c831c74a41c1ce84", + "CONTRIBUTING.md": "0f4d2d703febb566c2a03aa94684be12915ecf8ca022bed118321214c9efce58", "README.md": "83ea436685782c5c2d2d375ceae21cb95c72a5f6608eb8187a5efc817350e081", "assets/boatstack-journey.svg": "c1f7fe2741f5e9ca66bb3fe9b103e6364ba5acbca8b7a8054768ffd85cf325ea", "assets/boatstack-mark.svg": "ec96165583b15cfd446c27049d49217973f3e9b1defa5771cc08eec0c9542ce4", @@ -58,8 +58,8 @@ "boatstack/runtime.go": "b988d57ec14e15fc6a57949a995879fc0e0d6bfa9a7b62935e7754df0b85d87a", "boatstack/runtime_cache.go": "ab0fbb7f8a2eb8d8428e928fbc3d8866c84104e7cb330a901c121dfec82cddb3", "boatstack/runtime_cache_test.go": "4cbca9dec7800d7df6e3ec0d74c7ecbe1508e5c5a288d863f35fc8d22986c308", - "boatstack/safety.go": "0921f53df1d86470ef2b0f627f43829d2a7e73c0e5ff0b4195aaaf576aea9325", - "boatstack/safety_test.go": "62375fd640d543ab8875c7b31fd935ac7f5385830f625123f44508e629b4ff08", + "boatstack/safety.go": "4b4ac600f0ef3c3800904e06834bd39f3887b822244b4a1fd5af7330ae91887c", + "boatstack/safety_test.go": "03885d5a93f42b6adba6eef6bbef0680d81c0e1442fb72626a105da4862aecdf", "boatstack/testdata/reviewer-pr-body.md": "4c64e3788e5d61a377aeb0f797f7fc8d2316ab6e49572d15636eea7ba9e34ac4", "boatstack/testdata/safety/safe_apply.py.txt": "c9ec7fb932cf21b6aa8df597c4d4c54d6ec65e796240e49118d699f583383975", "boatstack/testdata/safety/unsafe_apply.py.txt": "42db1751865cc15c4dd69a03146b5deca8f21f916d258e433b27bbef5f884ab1", @@ -68,10 +68,10 @@ "docs/account-recovery-walkthrough.md": "676034974594a7d1a559b24dbed31d7ccc429eb81404b203ca07bbdaa19ec3d3", "docs/benchmark-corpus-audit.md": "f2d206fe8579a514f9da82b2c96c19b343ac004be67617e1bd34f0f8e0e5e6c6", "docs/benchmark-submission-audit.md": "9518abdd17690729c6423f87cab20418ed47b0915b5faa44b9ef975e9e9c3b79", - "docs/evidence-engineered-coding.md": "99f014ad57b52a3ec706f822da5c37346ed492b0677b7f5e697ec5694a7911aa", + "docs/evidence-engineered-coding.md": "03dc197a7fd3024911c23c93c34e1e2e417426493aa31ee603b86c504d71519e", "docs/generated-files.md": "7b2e8c10a35aa351fb87753492ed3cadb05011002d2fd6ffeb1951c356f6b286", "docs/getting-started.md": "6d98555b9d7a27091169a6a8c1efb64c84791c73a72f814e2a4dbdc149ac58a6", - "docs/public-claims.json": "3f750849f4dec8ed7273a8bf116e8d067f145ba9e4c06c7082f56ef18359de10", + "docs/public-claims.json": "192b0333ce701af1534ceb4cd3ee2f3e8ff09085a247dffe3240a9fabb100c49", "docs/public-surface.md": "713f7a050b5f339cf948299103ef3800417dccfecf2cc1a4166397ea6f978907", "docs/research-and-design.md": "d65c66e323037bda5d45aacef5d48afa6bf93da55901378891d235aca3a5684f", "docs/safety.md": "7b9b5c515d36e683767ec8d3d9d6d119ac93650b2f629d351deadd4c600ed6a6", @@ -85,7 +85,7 @@ "labs/diagram-json/compiled/evidence.md": "1ba1c989ade070a8ef9a508fbd788d100d7292f2dbacbb2bce895468019f619d", "labs/diagram-json/compiled/tasks.json": "88f60851abf79d851e9fccc754ff3040034ae595306bc87d64784c19eb403e71", "labs/diagram-json/compiled/test-matrix.json": "424657ff505768e50fa113801fd8363364a18269d5297480907a993d44063a39", - "labs/diagram-json/plan.lock.json": "f6cced0f67a01aa1c2d1621572e31cf3f2ff734064edf94afdf60391624d6751", + "labs/diagram-json/plan.lock.json": "3860c98ddc84b7ab1a2e9038fa92a7dedac05b4fa823cc5db763fd4412cf3c7a", "labs/diagram-json/plan.md": "3cc4f533b8d69386deff16b3a594a3ba09d4c0c3db636cccd8c4380084ce6a51", "labs/diagram-json/questions.md": "74733b015002c8a6777c558e7e997fa48c94850b9bd39054fe9366c97ecf728d", "labs/diagram-json/request.md": "0808fc41c36779c404f4a3a121167da6e76cac56df526e70f9ed6d3e0d4c02ed", @@ -100,12 +100,13 @@ "release-notes/2026-07-18-global-reply-shortcuts.md": "329d6fd104079bc5f66e7c3d477f4ff2a6bb264d429485c6f42f9c203d17fa29", "release-notes/2026-07-18-harbor-lab-namespace.md": "6419c049e5a3024c5a8604e4d9fb241c27ceb80bf1d4cc62f66d1a0eaf09ea21", "release-notes/2026-07-18-intelligence-flow-labs.md": "b236dddcf22dab718698b05c5dcf162ffddf9f5b53ea98468fd49b342d75edb9", + "release-notes/2026-07-18-safety-sql-boundaries.md": "32011ca3d02a371e8f3f2899ffb34df3af0843d18d25e7db95fbca32c2dcf18c", "release-notes/2026-07-18-stacked-bar-mark.md": "c4d5bd5fb89c280d7fba015384fd795fcb8c31ffe501078aa55a90cbcf66ba7b" }, "generator": "operatorstack/intelligence-flow:boatstack-distribution", "schema_version": 1, "source": { - "commit": "936457567063d878f7bda40e3a828568c4210e56", + "commit": "ef0d18195ef87f96891ea35c96866c456c855b1d", "path": "labs/12-product-engineering-loop", "repository": "operatorstack/intelligence-flow" } diff --git a/boatstack/safety.go b/boatstack/safety.go index 7aae5d3..397b52d 100644 --- a/boatstack/safety.go +++ b/boatstack/safety.go @@ -46,7 +46,11 @@ var irreversiblePatterns = []struct { } var operationalPathPattern = regexp.MustCompile(`(?i)(?:^|/)(?:scripts?|migrations?|schema|database|db|deploy|infra|ops|terraform|k8s)(?:/|$)|\.(?:sql|ps1|sh|bash|py)$`) -var mutationStatementPattern = regexp.MustCompile(`(?is)\b(?:delete\s+from|update\s+[^\s;]+)\b[^;]*`) + +// Match SQL mutation grammar rather than isolated English or command tokens. +// Requiring DELETE FROM or UPDATE SET keeps executable SQL visible +// without treating names such as check-update or API method labels as queries. +var mutationStatementPattern = regexp.MustCompile(`(?is)\b(?:delete\s+from\s+(?:[a-z_][a-z0-9_$.-]*|"[^"]+")|update\s+(?:[a-z_][a-z0-9_$.-]*|"[^"]+")\s+set\b)[^;]*`) var directPublicationPattern = regexp.MustCompile(`(?i)(?:\bgit\b[^\n;&|]*\bpush\b|\bgh\s+pr\s+(?:create|edit|ready|merge)\b|\bgh\s+api\b[^\n;&|]*(?:/pulls\b|/pull-requests\b)|\bhub\s+pull-request\b|\bcurl\b[^\n;&|]*(?:api\.github\.com|/pulls\b)[^\n;&|]*(?:\s-X\s*(?:POST|PATCH)|--request\s+(?:POST|PATCH)))`) var approvedPublisherPattern = regexp.MustCompile(`(?i)^\s*(?:[^\s]*/)?boatstack-helper\s+publish-pr\b[^\n;&|]*$`) var deliveryStatePathPattern = regexp.MustCompile(`(?i)(?:boatstack[/\\]deliveries|\.git[/\\](?:worktrees[/\\][^/\\]+[/\\])?boatstack(?:[/\\]|$))`) diff --git a/boatstack/safety_test.go b/boatstack/safety_test.go index cc0ff17..3c01c75 100644 --- a/boatstack/safety_test.go +++ b/boatstack/safety_test.go @@ -88,6 +88,8 @@ func TestSafeDiagnosticsAndFixForwardCommandsRemainAllowed(t *testing.T) { `git diff -- scripts/apply_schema.py | head -20`, `python scripts/apply_schema.py --dry-run`, `psql -c "SELECT current_database()"`, + `.product-loop/bin/boatstack-helper check-update --repo . --force`, + `psql -c "UPDATE accounts SET active = false WHERE id = 7"`, } for _, command := range commands { if findings := ClassifyCommand(repo, command); len(findings) != 0 { @@ -96,6 +98,40 @@ func TestSafeDiagnosticsAndFixForwardCommandsRemainAllowed(t *testing.T) { } } +func TestAPIMethodNamesDoNotMasqueradeAsSQLMutations(t *testing.T) { + repo := safetyTestRepo(t) + path := filepath.Join(repo, "api", "main.py") + if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { + t.Fatal(err) + } + value := []byte("" + + "from fastapi import FastAPI\n" + + "from fastapi.middleware.cors import CORSMiddleware\n\n" + + "app = FastAPI()\n" + + "app.add_middleware(\n" + + " CORSMiddleware,\n" + + " allow_methods=[\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\"],\n" + + ")\n" + + "metadata.update({\"supported_method\": \"DELETE\"})\n") + if err := os.WriteFile(path, value, 0o644); err != nil { + t.Fatal(err) + } + if findings := ClassifyCommand(repo, "python api/main.py"); len(findings) != 0 { + t.Fatalf("ordinary API method configuration was denied: %#v", findings) + } + + runGit(t, repo, "add", "api/main.py") + runGit(t, repo, "commit", "-m", "add API") + runGit(t, repo, "switch", "-c", "feat/cors") + if err := os.WriteFile(path, append(value, []byte("# localhost ports 3000-3010\n")...), 0o644); err != nil { + t.Fatal(err) + } + report, err := CheckRepositorySafety(repo) + if err != nil || report.Status != "PASS" { + t.Fatalf("CORS operational diff was denied: %#v %v", report, err) + } +} + func TestInvokedRepositoryScriptIsInspected(t *testing.T) { repo := safetyTestRepo(t) path := filepath.Join(repo, "scripts", "apply_schema.py") diff --git a/docs/evidence-engineered-coding.md b/docs/evidence-engineered-coding.md index c1e3b15..147b491 100644 --- a/docs/evidence-engineered-coding.md +++ b/docs/evidence-engineered-coding.md @@ -146,6 +146,6 @@ Delivery and system improvement also remain separate. A failed task may suggest ## What is evidence-backed -The current moves were derived from the Intelligence Flow benchmark corpus and product-repository studies. The generated source commit is [`936457567063d878f7bda40e3a828568c4210e56`](https://github.com/operatorstack/intelligence-flow/tree/936457567063d878f7bda40e3a828568c4210e56/labs/12-product-engineering-loop). +The current moves were derived from the Intelligence Flow benchmark corpus and product-repository studies. The generated source commit is [`ef0d18195ef87f96891ea35c96866c456c855b1d`](https://github.com/operatorstack/intelligence-flow/tree/ef0d18195ef87f96891ea35c96866c456c855b1d/labs/12-product-engineering-loop). The evidence supports specific failure mechanisms and guardrails. It does not establish that Boatstack is optimal, that control-theory notation proves software quality, or that one workflow dominates every team. Those are evaluation questions, so the distribution preserves measurements, provenance, gaps, and negative results. diff --git a/docs/public-claims.json b/docs/public-claims.json index f8d12ce..ee19d19 100644 --- a/docs/public-claims.json +++ b/docs/public-claims.json @@ -1,6 +1,6 @@ { "schema_version": 1, - "source_commit": "936457567063d878f7bda40e3a828568c4210e56", + "source_commit": "ef0d18195ef87f96891ea35c96866c456c855b1d", "statuses": ["verified", "observed", "still_being_evaluated"], "claims": [ { @@ -12,7 +12,7 @@ "readable_evidence": "why-these-steps.md#portable-workflow-and-state", "implementation": ["../boatstack/export.go", "../boatstack/references/artifacts.md", "../boatstack/references/workflow.md"], "verification": ["../boatstack/export_test.go"], - "last_verified_version": "source:936457567063d878f7bda40e3a828568c4210e56" + "last_verified_version": "source:ef0d18195ef87f96891ea35c96866c456c855b1d" }, { "id": "human-decisions", @@ -23,7 +23,7 @@ "readable_evidence": "why-these-steps.md#human-decisions", "implementation": ["../boatstack/references/workflow.md", "../boatstack/plan.go"], "verification": ["../boatstack/plan_test.go", "../boatstack/planning_test.go"], - "last_verified_version": "source:936457567063d878f7bda40e3a828568c4210e56" + "last_verified_version": "source:ef0d18195ef87f96891ea35c96866c456c855b1d" }, { "id": "validation-provenance", @@ -34,7 +34,7 @@ "readable_evidence": "why-these-steps.md#validation-provenance", "implementation": ["validation-and-evidence.md", "../boatstack/plan.go"], "verification": ["../boatstack/plan_test.go"], - "last_verified_version": "source:936457567063d878f7bda40e3a828568c4210e56" + "last_verified_version": "source:ef0d18195ef87f96891ea35c96866c456c855b1d" }, { "id": "irreversible-operations", @@ -46,7 +46,7 @@ "readable_evidence": "why-these-steps.md#irreversible-operations", "implementation": ["safety.md", "../boatstack/safety.go", "../boatstack/hooks.go"], "verification": ["../boatstack/safety_test.go", "../boatstack/hooks_test.go"], - "last_verified_version": "source:936457567063d878f7bda40e3a828568c4210e56" + "last_verified_version": "source:ef0d18195ef87f96891ea35c96866c456c855b1d" }, { "id": "reviewer-ready-pr", @@ -57,7 +57,7 @@ "readable_evidence": "why-these-steps.md#reviewer-ready-pr", "implementation": ["../boatstack/pr.go", "getting-started.md"], "verification": ["../boatstack/pr_test.go"], - "last_verified_version": "source:936457567063d878f7bda40e3a828568c4210e56" + "last_verified_version": "source:ef0d18195ef87f96891ea35c96866c456c855b1d" }, { "id": "phase-scoped-delivery", @@ -68,7 +68,7 @@ "readable_evidence": "why-these-steps.md#phase-scoped-delivery", "implementation": ["../boatstack/delivery.go", "../boatstack/safety.go", "../boatstack/hooks.go", "../boatstack/references/workflow.md"], "verification": ["../boatstack/delivery_test.go", "../boatstack/pr_test.go"], - "last_verified_version": "source:936457567063d878f7bda40e3a828568c4210e56" + "last_verified_version": "source:ef0d18195ef87f96891ea35c96866c456c855b1d" }, { "id": "model-neutral-contract", @@ -79,7 +79,7 @@ "readable_evidence": "why-these-steps.md#model-choice-and-budget", "implementation": ["research-and-design.md", "../boatstack/references/workflow.md"], "verification": ["../boatstack/export_test.go", "../boatstack/planning_test.go"], - "last_verified_version": "source:936457567063d878f7bda40e3a828568c4210e56" + "last_verified_version": "source:ef0d18195ef87f96891ea35c96866c456c855b1d" }, { "id": "cross-model-failures", @@ -90,7 +90,7 @@ "readable_evidence": "why-these-steps.md#model-choice-and-budget", "implementation": ["research-and-design.md"], "verification": ["benchmark-corpus-audit.md", "benchmark-submission-audit.md"], - "last_verified_version": "source:936457567063d878f7bda40e3a828568c4210e56" + "last_verified_version": "source:ef0d18195ef87f96891ea35c96866c456c855b1d" }, { "id": "lower-cost-outcomes", @@ -101,7 +101,7 @@ "readable_evidence": "why-these-steps.md#model-choice-and-budget", "implementation": ["research-and-design.md"], "verification": ["benchmark-corpus-audit.md", "benchmark-submission-audit.md"], - "last_verified_version": "source:936457567063d878f7bda40e3a828568c4210e56" + "last_verified_version": "source:ef0d18195ef87f96891ea35c96866c456c855b1d" }, { "id": "git-worktree-activation", @@ -112,7 +112,7 @@ "readable_evidence": "why-these-steps.md#git-worktree-activation", "implementation": ["../boatstack/runtime_cache.go", "../boatstack/hooks.go"], "verification": ["../boatstack/runtime_cache_test.go", "../boatstack/hooks_test.go"], - "last_verified_version": "source:936457567063d878f7bda40e3a828568c4210e56" + "last_verified_version": "source:ef0d18195ef87f96891ea35c96866c456c855b1d" }, { "id": "visible-updates", @@ -123,7 +123,7 @@ "readable_evidence": "why-these-steps.md#visible-updates", "implementation": ["../boatstack/update.go", "../boatstack/init.go"], "verification": ["../boatstack/update_test.go", "../boatstack/init_test.go", "../boatstack/export_test.go"], - "last_verified_version": "source:936457567063d878f7bda40e3a828568c4210e56" + "last_verified_version": "source:ef0d18195ef87f96891ea35c96866c456c855b1d" } ] } diff --git a/labs/diagram-json/plan.lock.json b/labs/diagram-json/plan.lock.json index b9b2dc2..a0dc8f6 100644 --- a/labs/diagram-json/plan.lock.json +++ b/labs/diagram-json/plan.lock.json @@ -6,7 +6,7 @@ "plan_path": "labs/diagram-json/plan.md", "plan_sha256": "3cc4f533b8d69386deff16b3a594a3ba09d4c0c3db636cccd8c4380084ce6a51", "schema_version": 1, - "source_commit": "936457567063d878f7bda40e3a828568c4210e56", + "source_commit": "ef0d18195ef87f96891ea35c96866c456c855b1d", "source_plan_path": "labs/diagram-json/source-plan.md", "source_plan_sha256": "e10593ddaa7522ab80cc991d0a09399257139799e37f737794cd49d68a39985b", "spec_path": "labs/diagram-json/spec.md", diff --git a/release-notes/2026-07-18-safety-sql-boundaries.md b/release-notes/2026-07-18-safety-sql-boundaries.md new file mode 100644 index 0000000..d4b35a2 --- /dev/null +++ b/release-notes/2026-07-18-safety-sql-boundaries.md @@ -0,0 +1,3 @@ +### Safety checks distinguish SQL from ordinary code + +Boatstack no longer blocks release checks whose command contains `check-update` or Python API files that configure the `DELETE` HTTP method. Real unbounded SQL `DELETE FROM` and `UPDATE … SET` operations remain denied, while bounded updates and ordinary product commits can proceed through the normal agent workflow.