From 2d76ebc0ad9389879b84a52af1670780265f5c7f Mon Sep 17 00:00:00 2001 From: Ben Fellows Date: Mon, 3 Aug 2026 18:20:40 +1200 Subject: [PATCH 1/2] Refresh the docs against what N-11 actually shipped First real staleness check on user-docs/, three days after writing it, and two pages had drifted. Both were claims about things that changed underneath them, which is exactly the failure mode the source-of-truth footers exist to catch. The architecture page said the quick-create link carries four parameters. It carries five: N-11 phase 2 added TopsInstallId, and the parent subscription now only forwards messages carrying that value while the rest land in a quarantine queue. That is a materially better story for the audience this page is written for, so it is worth saying properly rather than leaving a stale count. SECURITY.md listed three known issues, two of which are now closed -- #100 shipped and #102's template is deleted. A vulnerability policy telling researchers not to report things that are already fixed is worse than useless: it discourages reporting a regression. #101 stays, reworded to describe what is now in place rather than what was open when it was written, and #109 takes the freed slot with an honest note that it is dead permission rather than exposure. Verified rather than assumed: the IAM permissions page still holds exactly -- 21 inline policies, 3 resource-scoped, 18 unscoped, 2 managed, 2 roles -- and the findings pages' 74 rules and 4/24/32/14 severity split are unchanged. No page referenced the deleted audit template except the SECURITY.md row now removed. Co-Authored-By: Claude Opus 5 --- SECURITY.md | 5 ++--- user-docs/start-here/how-tops-connects-to-aws.md | 11 +++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 5161741..bf558c2 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -85,9 +85,8 @@ These are public, tracked, and being worked on. Reporting them again is not a fi | | | | --- | --- | -| [#101](https://github.com/teemops/tops/issues/101) | The parent account's `teemops-sns` topic accepts `sns:Publish` from any AWS principal. Publish-only, and acting on a message still requires guessing a 122-bit `external_id`, but it is open and it is being fixed. The issue links the full research and the options considered | -| [#100](https://github.com/teemops/tops/issues/100) | The account-linking consumer does not cross-check the account in `TopsRoleArn` against the one in `StackId`, nor require a `pending` status | -| [#102](https://github.com/teemops/tops/issues/102) | `templates/iam.role.audit.account.cfn.yaml` defaults to a vendor AWS account and is not on the onboarding path | +| [#101](https://github.com/teemops/tops/issues/101) | The parent account's `teemops-sns` topic accepts `sns:Publish` from any AWS principal. The subscription now screens messages on a per-install id and quarantines the rest, so a forged publish does not reach the queue — but the topic itself is still openly publishable, and the issue stays open until that is closed off. Background: [`docs/features/sns-topic-publish-authorization.md`](docs/features/sns-topic-publish-authorization.md) | +| [#109](https://github.com/teemops/tops/issues/109) | The `teemops_main` queue policy grants `SQS:ReceiveMessage` to `Principal: "*"`. The `aws:SourceArn` condition means it cannot actually authorise a direct caller, so it is dead permission rather than exposure — but it is known, and being removed | ## Supported versions diff --git a/user-docs/start-here/how-tops-connects-to-aws.md b/user-docs/start-here/how-tops-connects-to-aws.md index 9db4adc..8f62c0b 100644 --- a/user-docs/start-here/how-tops-connects-to-aws.md +++ b/user-docs/start-here/how-tops-connects-to-aws.md @@ -56,12 +56,15 @@ alone. The administrator creates the stack in their own console, under their own [![Diagram: TOPS generates a CloudFormation quick-create URL; the child account admin creates a stack that makes a cross-account IAM role plus a custom resource; the custom resource publishes the role ARN to the parent SNS topic; the TOPS worker long-polls SQS, matches it and stores it, then replies to CloudFormation.](../assets/diagrams/aws-child-account-linking.svg)](../assets/diagrams/aws-child-account-linking.svg) -1. **Hand over a link.** A console quick-create URL carrying four parameters: your parent - account id, the region, the account's `ExternalId` and its `UniqueId`. +1. **Hand over a link.** A console quick-create URL carrying five parameters: your parent + account id, the region, the account's `ExternalId`, its `UniqueId`, and a `TopsInstallId` + that identifies your installation. 2. **The admin creates the stack.** In their account, with their permissions. TOPS has no session there and cannot create it for them. -3. **The stack calls home.** A custom resource publishes the new role ARN, external id and - unique id to your SNS topic, which fans into `teemops_main`. +3. **The stack calls home.** A custom resource publishes the new role ARN, external id, + unique id and install id to your SNS topic. The topic's subscription only forwards + messages carrying *your* install id into `teemops_main`; anything else goes to a + quarantine queue you can inspect, so a mismatched link fails visibly instead of silently. 4. **Your worker picks it up.** Outbound long-poll from inside your network. The message is accepted only if both ids match a record you already created. 5. **The stack completes.** TOPS replies to the CloudFormation `ResponseURL`; the admin sees From f6a391a3ebae60a620b42af511afc270014323ff Mon Sep 17 00:00:00 2001 From: Ben Fellows Date: Mon, 3 Aug 2026 18:24:11 +1200 Subject: [PATCH 2/2] Mark the vulnerability-reporting gap closed GitHub private vulnerability reporting is enabled on the repo -- verified via the API rather than assumed -- and security@teemops.com is routed. Both channels SECURITY.md names now answer, so the caveat recorded against it comes off. SECURITY.md itself needed no change: it was written naming both channels on the assumption they would exist, which is now true. Co-Authored-By: Claude Opus 5 --- design/docs-site/information-architecture.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/design/docs-site/information-architecture.md b/design/docs-site/information-architecture.md index 42c5bb2..ef105cd 100644 --- a/design/docs-site/information-architecture.md +++ b/design/docs-site/information-architecture.md @@ -150,7 +150,7 @@ somewhere and needs porting and a change of voice, not that a `user-docs/` page | **Security** | | The security model | Evaluator | ✅ **Built this session** | The architecture page's boundary table | **1** | | Where your data lives | Evaluator | ✍️ Write | Nothing leaves the install — needs stating plainly | 2 | -| Reporting a vulnerability | Evaluator | ✍️ Write | No `SECURITY.md` exists — **gap** | **1** | +| Reporting a vulnerability | Evaluator | ✅ **Done** | `SECURITY.md` — link to it rather than restating it | **1** | | Licence and trademark | Evaluator | ✅ Exists | `LICENSE`, `TRADEMARK.md`, roadmap D-7 | 3 | | **Reference** | | Glossary | All | ✅ Exists | `docs/GLOSSARY.md` | 3 | @@ -164,13 +164,12 @@ job, which is the argument for doing the IA before the writing. ### Two gaps this inventory exposed -1. ~~**There is no `SECURITY.md`.**~~ **Written 2026-08-02.** A public repo with a `security` +1. ~~**There is no `SECURITY.md`.**~~ **Closed 2026-08-03.** A public repo with a `security` label, three open security issues and a CISO-facing architecture page had nowhere to report a vulnerability, and `README.md` said "open an issue" — precisely the wrong advice. - Now at the repository root, with the README pointing to it. **Two follow-ups it depends - on:** GitHub private vulnerability reporting must be enabled (it is currently off), and - `security@teemops.com` must be created and routed. Until both are done the policy names - channels that do not answer. + `SECURITY.md` is now at the repository root with the README pointing to it, GitHub private + vulnerability reporting is enabled, and `security@teemops.com` is routed. Both channels the + policy names now answer. 2. **`docs/quick-start.md` is dead.** It describes a Nuxt 3 + Serverless + Prisma monorepo — the pre-pivot stack. It is linked from `docs/README.md` and would mislead anyone who found it. Delete it rather than port it. @@ -246,8 +245,7 @@ against the roadmap — the roadmap describes intent, `PROGRESS.md` describes th Priority in the inventory says what matters; this says what unblocks what. Roughly dependency order, not importance order. -1. **`SECURITY.md`** — repo hygiene, blocked by nothing, and the one gap with an active - reason to exist today. +1. ~~**`SECURITY.md`**~~ — done 2026-08-03, with both reporting channels live. 2. **The two evaluator pages** — already written. *How TOPS connects to AWS* is done; *What the IAM role can do* is a straight extraction from it and the child template. 3. **Reading a finding**, then **Resolving a finding.** In that order: resolution is