Repository navigation
feat: security notices reach every owner's phone, copy or not, and the car class is held - #23
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0647def7e2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return ok && known && d.Epoch == epoch && (getsNotices(d, kindName, app) || | ||
| slices.Contains(d.Scopes, k.scope) && slices.Contains(r.Grant.Scopes, k.scope)) |
There was a problem hiding this comment.
Filter alerts against the roster being applied
When a new roster removes ftw.events.read from an owner, this branch deliberately retains the owner's alert token for notices, but sendAlert determines event access by rereading the persisted roster. In uplink.roster, OnRoster runs before registry.SetRoster, so an alert worker running in that interval sees the old event-enabled roster and can send a queued event or box.unreachable notification after access was withdrawn. Retain the current roster in the push service for audience checks, or persist it before exposing the retained token.
Useful? React with 👍 / 👎.
… car class is held A box's signed notice goes to the home's owner phones in an alert, as the box signed it, with the readable copy on or off, and never to a viewer or a watch. An owner's phone may register for alerts without the copy for this, and a roster keeps that token. A notice holding anything beyond its kind and, on agent.added, the client's name is dropped and counted. Notices have their own hourly cap, counted as they come, reach an owner another owner suspended, and Apple may hold them for a day. Events and box.unreachable go only to devices the newest roster lets read events, and an event of a notice's kind is dropped. An alert over APNs' 4 KB never queues. A box that has sent no roster gets no notice through. The pin moves to srcfl/ftw c41e6e98 (#1661 with master, QUIC included), which also carries master's car class: the service holds car like the other copy classes and serves it under ftw.live.read; a token never reads it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
0647def to
304c9e4
Compare
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What
Two things now reach the phones through the service. The box halves are srcfl/ftw#1661 (notices) and srcfl/ftw#1662 (the car class); the phone half is srcfl/ftw-app#77.
Security notices
Until now the uplink dropped a box's
noticeas an unknown class, so no owner heard of a new agent, an approval waiting, a new approval key, a new owner or a grant about to run out.uplink: a signednoticegoes to a new hook,OnNotice, with the readable copy on or off. The service holds none of it.uplink: only once the home holds a roster, so a box that has sent none spends nothing. Not behindServing(): that is the readable copy, and a notice must go with the copy off.push.Notice: checks the body withcloudwire.ReadNotice(a 16-byte boot,kind, and onagent.addedthe client's name, nothing else), counts it against the home's notice cap as it comes, refuses a payload over APNs' 4 KB, then sends the box's envelope unchanged in an alert, through feat: a seam for shards, a quicker hot path, metrics, deploys without a storm, and a load harness #17's alert queue, with a 24-hour APNs expiry. A notice that is not one is dropped, counted (push_notice_not_a_notice) and logged. Theapsis the same as every other alert's; the phone writes the words.push_event_of_a_notice_kind): a box on #1646 sends one as both, and the event path reaches viewers.ftw.events.readin its effective scope.box.unreachablego only to devices the newest roster lets read events (push.audience, which reads the signed roster the registry holds), so an owner registered for notices alone gets no event if one arrives.registry.PushPrunekeys a registration by its app too, so an owner's watch-app token goes with events.The car class
The pin moves to srcfl/ftw c41e6e98 (#1661's branch with master merged in, QUIC included), which carries master's
carclass (#1647). Rebased on main after #16 and #22;go mod tidyleaves no straygithub.com/srcfl/ftw … +incompatibleline in go.sum. The service holdscarlike the other copy classes, as the box sent it, and serves it underftw.live.read. A token (/v1/now) never reads it.Size
Non-test Go:
internal/push+158 / −20 (1,167 lines now),internal/uplink+17 (1,035),internal/registry+8 / −7,cmd/ftwcloudd+1. About 157 lines net. The whole service is about 18,300 lines of non-test Go, well past the 3,000 in CLAUDE.md before this PR.Deploy order
Cloud first (this), then boxes (srcfl/ftw#1661, #1662), then phones (srcfl/ftw-app#77).
Tests
push: an event of each notice kind is dropped and an ordinary one still goes (TestAnEventOfANoticeKindIsDropped); a suspended owner gets no event but every notice, and a notice expires in 24 h (TestASuspendedOwnerStillGetsNotices); an alert over 4 KB never queues. With the copy off, a notice gives one alert per owner phone and none to a viewer or a watch, who registered while the copy was on and lost their tokens with it; with the copy on, the same owners only; an event with the copy off goes to nobody (TestANoticeGoesToEachOwnerPhoneWithTheCopyOff). An owner's phone registers with the copy off; a viewer, a watch and an owner's watch app do not. A notice holding a reading, a source id or another kind, or an event's envelope, reaches nobody (TestANoticeCannotCarryReadings). Notices have their own cap. Three earlier tests now expect an owner to keep its alert token without events.uplink: a notice reaches the hook unchanged with the copy off and the service holds nothing (TestANoticeReachesPushWithTheCopyOff); a notice before any roster goes nowhere; the car class is held and served under live, and not without it.store: a token reads no car.go vet ./... && go test -race ./...,go test -tags ftwclouddev ./...andscripts/check-imports.sh: green with-p 2.Before merge
After #1661 merges, move the
go/protocolpin to its merge commit and rungo mod tidy.🤖 Generated with Claude Code