Skip to content

feat(engine): sync confidential opt-out + threat model (#22, #23)#72

Merged
mopanc merged 1 commit into
mainfrom
feat/sync-confidential-opt-out-and-security-md
May 11, 2026
Merged

feat(engine): sync confidential opt-out + threat model (#22, #23)#72
mopanc merged 1 commit into
mainfrom
feat/sync-confidential-opt-out-and-security-md

Conversation

@mopanc
Copy link
Copy Markdown
Owner

@mopanc mopanc commented May 11, 2026

Summary

Bundle E of the v1.0.0-rc.1 plan — closes the two remaining security-roadmap gaps that block tagging rc.1.

  • S0-10 sensitivity: confidential opt-out from sync (security gap C) #22sensitivity: confidential opt-out from sync (gap C). saga sync scans the layer notes dir, parses frontmatter, and excludes matched files from git add via a :(exclude)<path> pathspec. Confidential files stay on disk, never staged, never pushed. A new --dry-run flag prints the plan (pending + excluded) without mutating anything. If a confidential topic's file already exists in origin/<branch> (was pushed previously), sync emits a warning explaining that local marking is not retroactive and pointing to a manual cleanup workflow until saga sync --purge lands.
  • S0-11 SECURITY.md threat model update (security gap D) #23 — SECURITY.md threat model (gap D). SECURITY.md rewritten with: Threat model (what Saga protects / what it does not), Trust boundaries, Storage at rest (and why no encryption at rest in v1), Sync transport, Secret handling (pattern list), sensitivity: confidential semantics, Scope, Disclosure. README gets a short "Security model" section linking into it.

One non-trivial design decision

The personal layer seed previously defaulted to sensitivity_default: confidential. With #22 implemented as the issue describes, that default would make every new topic local-only — defeating the entire point of a syncable personal layer. Flipped to internal. confidential is now the explicit per-topic opt-out the issue asks for (credentials notes, medical info, etc.).

The change only affects new installs. Existing layers keep whatever value is already in their meta.yml — users with the old default can migrate at their own pace.

Test plan

  • go test ./... — full suite green
  • golangci-lint run — 0 issues
  • New tests in internal/saga/sync_test.go:
    • TestSyncExcludesConfidentialTopicsFromPush — confidential file does not appear in remote clone after sync
    • TestSyncConfidentialFileStaysLocal — file remains on disk after sync
    • TestSyncDryRunListsPendingAndExcluded — dry-run reports plan without committing/pushing
    • TestSyncWarnsWhenConfidentialAlreadyInRemote — flipping a pushed topic to confidential surfaces the warning
    • TestSyncNoWarningWhenConfidentialNeverPushed — clean case stays warning-free
  • Manual smoke on Jorge's actual layer (post-merge, after the seed-default migration)

Closes #22
Closes #23

#22 — `sensitivity: confidential` opt-out from sync (security gap C)

Topics with frontmatter `sensitivity: confidential` are kept local-only:
- `saga sync` scans the layer notes dir, parses frontmatter, and excludes
  matched files from `git add` via a pathspec (`:(exclude)<path>`). The file
  stays on disk untracked / unstaged.
- New `--dry-run` flag prints the push plan (pending + excluded) without
  staging, committing, pulling, or pushing.
- When a confidential topic's file already exists in `origin/<branch>` (was
  pushed previously), sync emits a warning explaining that local marking is
  not retroactive and pointing to a manual `git rm --cached` workflow until
  `saga sync --purge` lands.
- Personal layer seed default flipped from `confidential` to `internal`:
  the layer-default of confidential contradicted the very design of a
  syncable layer. Confidential is now an explicit per-topic opt-out for
  the rare cases (credentials notes, medical info, etc.).
- Existing installs keep whatever value already in their meta.yml; only
  new `saga` installs see the new default.

Tests: confidential excluded from remote, file stays local, dry-run reports
plan without mutation, warning fires on previously-pushed flip, no warning
on never-pushed confidential.

#23 — SECURITY.md threat model (security gap D)

Rewritten with the sections #23 asks for: Threat model (what Saga protects /
what it does not), Trust boundaries, Storage at rest (and why no encryption
at rest in v1), Sync transport, Secret handling (pattern list), `sensitivity:
confidential` semantics (what it does / does not do), Scope, Disclosure.
Explicitly documents v1 limitations: no encryption at rest (v2 opt-in via
DESIGN_v2.md), no per-topic ACL beyond confidential, agent that writes via
`topic_write` is trusted.

README gets a short "Security model" section that links into SECURITY.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mopanc mopanc merged commit f0a0410 into main May 11, 2026
6 checks passed
@mopanc mopanc deleted the feat/sync-confidential-opt-out-and-security-md branch May 11, 2026 18:49
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.

S0-11 SECURITY.md threat model update (security gap D) S0-10 sensitivity: confidential opt-out from sync (security gap C)

1 participant