Skip to content

Adapt according to new visibility rules - #433

Draft
jcp19 wants to merge 13 commits into
masterfrom
claude/scion-visibility-rules-dvh0uo
Draft

Adapt according to new visibility rules#433
jcp19 wants to merge 13 commits into
masterfrom
claude/scion-visibility-rules-dvh0uo

Conversation

@jcp19

@jcp19 jcp19 commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

claude added 5 commits August 13, 2026 21:28
Gobra now enforces Go's visibility rules (viperproject/gobra#1092): importing
packages may only reference exported members, contracts of exported members may
only mention exported names, and the bodies of fully-public predicates and pure
functions may only reference exported members.

verification/io is a purely ghost specification package whose members are all
part of the interface used by the router, so every member (and every ghost
struct field) is now exported. The redundant DataPlaneSpec.asid() alias for
Asid() is dropped. Ghost struct types of the package are annotated as
comparable, since importers compare their values with '=='.

The same treatment is applied to the ghost helpers of pkg/slayers/path and
pkg/slayers/path/scion that the router relies on, and monoset/resalgebra
predicates and pure functions whose bodies expose private state are marked
closed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txb3nNXx2mRUF6uae7PsRL
- pkg/addr: export the ghost helpers used in contracts of exported members and
  add AS.InRange, the ghost counterpart of the non-exported method inRange.
- pkg/slayers: spell out the memory of the non-exported extnBase in the
  predicates of the exported extension headers, so importers can unfold them;
  wrap the private state of SCMP and of the SCION path pool in closed
  predicates and expose constructors/lemmas for it; export the ghost address
  predicates and the ghost counterpart of scmpRawInterfaceLen; mark
  SCMPTypeCodeMem closed.
- Annotate the exported struct types compared with '==' across package
  boundaries as comparable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txb3nNXx2mRUF6uae7PsRL
…ility rules

Close the predicates and pure functions whose bodies expose private state
(gopacket.PkgMem/Registered, big.Int.Mem), export the members that importing
packages rely on (big.Int.ToInt, net.IsZeros), describe gopacket.NewFlow's
result through closed accessors instead of the private fields of Flow, give
interface members exported names, and annotate gopacket.Flow as comparable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txb3nNXx2mRUF6uae7PsRL
The contracts of exported members, and the bodies of fully-public predicates
and pure functions, may only reference exported members. In the router this is
achieved by closing the predicates and pure functions that describe the private
state of the dataplane (Mem, MutexInvariant, the getDom* accessors, ...),
by exporting the ghost members that occur in contracts of exported members, and
by wrapping the non-exported mutex of the dataplane in the closed predicate
MtxInv. The two ghost lemmas whose contracts expose non-exported fields are no
longer exported. AuthCarrier's ghost fields are exported because the methods
that use them implement resalgebra.RA and can therefore not be closed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txb3nNXx2mRUF6uae7PsRL
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txb3nNXx2mRUF6uae7PsRL
Comment thread verification/dependencies/github.com/google/gopacket/layers/tcpip.gobra Outdated
Comment thread pkg/slayers/scion_spec.gobra Outdated
Comment thread pkg/slayers/scion_spec.gobra Outdated
Comment thread pkg/slayers/scmp.go Outdated
Comment on lines 240 to 252
// NewSCMP allocates a new SCMP layer with the given type code. Importing
// packages cannot establish the layer's predicates themselves, because those
// cover the private state of the layer; this constructor is how they obtain a
// usable layer.
// @ ensures s != nil
// @ ensures s.NonInitMem()
// @ decreases
func NewSCMP(typeCode SCMPTypeCode) (s *SCMP) {
s = &SCMP{TypeCode: typeCode}
// @ fold s.ChecksumNetworkLayerMem()
// @ fold s.NonInitMem()
return s
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete this

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead, you could add a ghost method that takes permissions to all fields of a &SCMP and establishes s.NonInitMem(), as long as its pre is *s === SCMP{}

Comment thread pkg/slayers/scmp_spec.gobra Outdated
Comment thread router/dataplane.go Outdated
Comment thread router/dataplane.go Outdated
claude added 2 commits August 15, 2026 14:48
- Drop the unused tcpipchecksum/tcpipPseudoHeader stub instead of renaming a
  non-ghost interface method of gopacket/layers.
- Keep PathPoolMem and PathPoolMemExceptOne exported, and give the new closed
  predicates over the private path pool distinct names.
- Do not specify permission amounts in the preconditions and unfolding
  expressions of the pure functions introduced here.
- Replace the NewSCMP constructor by a ghost lemma that turns full permission
  to a zero-valued SCMP layer into its NonInitMem predicate, and use it at the
  two call sites in the router.
- Reword the comment on SCMP.ChecksumNetworkLayerMem as suggested.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txb3nNXx2mRUF6uae7PsRL
Gobra reserves the identifier 'Token' for a built-in member predicate
(TokenMPredTag in BuiltInMemberTag.scala), which participates in name
resolution of every package. Exporting the IO-spec's 'token' predicate under
that name therefore made the declaration and all of its uses ambiguous
('got duplicate identifier Token'), and the failure cascaded into every
package importing verification/io.

Found by running the visibility-rules build of Gobra (viperproject/gobra#1092)
over the packages verified in CI.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txb3nNXx2mRUF6uae7PsRL
Comment thread router/dataplane.go Outdated
claude added 6 commits August 16, 2026 08:37
A package invariant is part of a package's public interface, so it may only
reference exported members. epic's 'dup pkgInvariant' named the non-exported
predicate postInitInvariant; the predicate is now exported, and closed, since
its body describes the private global state of the package.

Verified with the visibility-rules build of Gobra (viperproject/gobra#1092):
pkg/experimental/epic goes from 3 errors on master to 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txb3nNXx2mRUF6uae7PsRL
The visibility rules are not in a released Gobra yet, so the two new keywords
this branch introduced would not parse. Every occurrence is replaced by a
'// TODO(gobra#1092): closed' / '// TODO(gobra#1092): comparable' marker
directly above the declaration it applied to; re-enabling them is a matter of
uncommenting (the grammar accepts both modifiers on their own line).

The restructuring they go with -- exported ghost members, predicates split so
that the private part sits behind its own predicate, package invariants that
only name exported members -- is kept, since it is valid under the current
Gobra as well.

Also reverts the one change this branch had made to executable code: the SCMP
layer in prepareSCMP is built from a keyed struct literal again, as it was
before. It only had to be built from its zero value so that a client could
establish NonInitMem without folding a closed predicate, which is not a
requirement until gobra#1092 lands; a TODO records what to do then.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txb3nNXx2mRUF6uae7PsRL
master added lemmas and assertions that use the ghost members this branch
renamed (absPkt, validPktMetaHdr, io.upd_uinfo, path.ifsToIO_ifs, ...). The
conflicting hunks in router/dataplane.go and router/io-spec-lemmas.gobra are
resolved in favour of master's content, with this branch's renames re-applied
to it; the same renames are applied to the newly added
pkg/slayers/path/scion/lemmas.gobra.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txb3nNXx2mRUF6uae7PsRL
- HiddenPathPoolMemExceptOne now carries the bound on pathType that used
  to be provided by an earlier conjunct of SCION.Mem; without it, the
  call to getPathPure in the predicate body has no precondition.
- testRun folds the new MtxInv predicate before calling Run.
- handleSCMPTraceRouteRequest uses the EstablishNonInitMem lemma, like
  the other two client-side sites that build an SCMP layer.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txb3nNXx2mRUF6uae7PsRL
master's #439 relaxed WellConfigured and PreWellConfigured so that a router
need only terminate a subset of the interfaces of its AS, and added
KnownIfIDLemma and getDomInternalNextHopsLemma alongside them. The conflicting
hunks in router/dataplane_spec.gobra and router/dataplane_spec_test.gobra are
resolved in favour of master's content, with this branch's renames of the
getDom* accessors re-applied to it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txb3nNXx2mRUF6uae7PsRL
pkg/slayers was never reached by CI on this branch, because an earlier step
of the same job failed; these are the two places in the package that the
restructuring of the path pool into HiddenPathPoolMem(ExceptOne) broke.

ExtractAcc hands out access to the whole layer, so it now also unfolds the
predicate that holds the fields of the path pool, and folds it back in the
body of the wand it packages. The assertion in that body makes the facts
about the layer that unfolding Mem provides available for the permissions
that come from the left-hand side of the wand.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txb3nNXx2mRUF6uae7PsRL
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.

2 participants