test: prove internal package visibility
This commit is contained in:
@@ -3855,6 +3855,139 @@ preloader, parallel action scheduler, or network behavior. Normal local WW
|
||||
builds and tests remain offline, manifest-free, registry-free, database-free,
|
||||
CAS-free, and network-free.
|
||||
|
||||
### 11.15 Implemented internal-package import visibility
|
||||
|
||||
A source import whose complete canonical import path contains a directory
|
||||
component named exactly `internal` is now contextual. Locate the final such
|
||||
component. Its parent directory is the ownership boundary, and the import is
|
||||
legal only when the importing source package's canonical filesystem directory
|
||||
is that boundary or a descendant at a real path-component boundary. Thus
|
||||
`domain.client` may import `domain.internal.secret`, while `outsider` and
|
||||
`domainx.client` may not. `internalx` has no special meaning. For
|
||||
`domain.internal.outer.internal.deep`, the final `internal` wins and the owner
|
||||
is `domain.internal.outer`, not `domain`.
|
||||
|
||||
The complete dotted import identity determines whether the rule applies and
|
||||
how many components comprise the final `internal` plus its following suffix.
|
||||
WW removes those components from that source edge's resolved lexical target
|
||||
route, canonicalizes the resulting owner directory physically, and compares it
|
||||
with the already canonical physical importer directory. Stripping precedes
|
||||
physical canonicalization because a symlink at or below `internal` may point to
|
||||
a target with a different name or depth; an action spelling interned by an
|
||||
earlier edge is never reused for this contextual calculation. Cstage obtains
|
||||
directory canonicalization through `realpath`; WWstage uses its equivalent
|
||||
`chdir`/`getcwd` canonicalization. For explicit single-file compatibility
|
||||
roots, Cstage uses `realpath` and WWstage's component walker uses
|
||||
`lstat`/`readlink` plus the same canonical current-directory representation;
|
||||
both preserve component and trailing-directory semantics across symlinks. The
|
||||
equality-or-`/`-boundary comparison never uses a raw string prefix. This
|
||||
division is intentional: an unrelated physical
|
||||
ancestor literally named `internal` does not impose visibility on an import
|
||||
whose canonical identity has no such component, while a symlink spelling at or
|
||||
below an import-path `internal` cannot move the effective owner or importer.
|
||||
Explicit single-file compatibility roots use their canonicalized containing
|
||||
directory as the importer context. Directly selecting an internal directory as
|
||||
a command root remains legal because selection is not a source import.
|
||||
|
||||
Visibility is an import-edge property, not part of canonical package or action
|
||||
identity. Both drivers resolve the complete target, intern or reuse its one
|
||||
canonical production action, and then perform the importer-context check before
|
||||
accepting the source binding or dependency edge. Consequently an allowed
|
||||
importer may load and compile the target normally, but that cached action cannot
|
||||
authorize a later forbidden importer. Reversing requested products or visiting
|
||||
the forbidden importer first produces the same result. No declared package
|
||||
name, leaf, output name, product ordinal, storage locator, hash, or test variant
|
||||
participates in the decision. Legal edges therefore retain the existing
|
||||
owner-only byte-sorted unit, exact sorted/deduplicated direct `.wwi` compiler
|
||||
inputs, deterministic archive, and complete archive-only linker closure.
|
||||
|
||||
Cstage represents the rule with the bounded
|
||||
`sep_internal_parent_count`/`sep_internal_import_allowed` helpers in
|
||||
`cmd/ww/main.c`. WWstage has the isomorphic
|
||||
`sepinternalparentcount`/`sepinternalimportallowed` helpers in
|
||||
`selfhost/cmd/ww/main.ww`. Neither adds a package field, fixed-size package
|
||||
table, second action universe, or action-key input. A distinct
|
||||
`SEP_LOAD_INTERNAL` result propagates through the iterative loader. On rejection
|
||||
both stages emit the importing parser position followed by exactly:
|
||||
|
||||
```text
|
||||
use of internal package <canonical-import-path> not allowed
|
||||
```
|
||||
|
||||
The command returns immediately from graph loading, before directory-identity
|
||||
finalization, unit composition, workdir owner validation, stale-voucher
|
||||
invalidation, tool-identity recording, compiler, assembler, in-driver archive
|
||||
production, linker, publication, or execution. A cold rejection therefore
|
||||
commits no target/importer artifact or `.wwtool.*` state. A forbidden warm
|
||||
request cannot use a previously committed target to bypass the check and leaves
|
||||
the already committed target voucher and all tool records byte-unchanged.
|
||||
Allocation or path canonicalization failure remains a deterministic
|
||||
command-fatal pre-tool error; the visibility helper does not change stable
|
||||
package indices or growth behavior.
|
||||
|
||||
Every selected source file reaches the same driver scan. The rule therefore
|
||||
applies to ordinary production sources, same-package test sources in the
|
||||
internal production-plus-test variant, external `_test` sources, and real
|
||||
source imports inside the test-support package. Generated-main-to-variant,
|
||||
generated-main-to-support, and coordinator product wiring remain synthetic
|
||||
edges and are not retroactively treated as source imports. No coordinator
|
||||
change is required: `cmd/wwtest` only dispatches, and
|
||||
`internal/wwpackage/package.ww` only discovers and classifies source groups,
|
||||
constructs the union request, and runs the driver; neither resolves a source
|
||||
import or owns its importing position.
|
||||
|
||||
This follows only the pinned official Go 1.26.5 source at commit
|
||||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||||
|
||||
- `loadImport` resolves and reuses the canonical package first, then explicitly
|
||||
checks the rule on every import because the result depends on the importing
|
||||
code, and attaches the importing position
|
||||
([`pkg.go`, lines 787–791](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L787-L791)).
|
||||
- The rule is the tree rooted at the parent of the target's `internal`
|
||||
directory
|
||||
([`pkg.go`, lines 1463–1471](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1463-L1471)).
|
||||
A package named directly on the command line is not an import
|
||||
([lines 1498–1502](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1498-L1502)),
|
||||
and the import-path boundary is located before filesystem containment
|
||||
([lines 1505–1515](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1505-L1515)).
|
||||
- Go's filesystem branch cleans the importer and owner, requires a
|
||||
path-component-aware prefix, and retries with both paths symlink-expanded
|
||||
([`pkg.go`, lines 1534–1546](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1534-L1546)).
|
||||
Its rejection text is exactly the diagnostic above
|
||||
([lines 1564–1571](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1564-L1571)),
|
||||
and its exact-component search deliberately selects the final `internal`
|
||||
element as the most restrictive rule
|
||||
([lines 1574–1590](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1574-L1590)).
|
||||
- Same-package and external test imports both pass through ordinary
|
||||
`loadImport` with their own source positions before variant construction
|
||||
([`test.go`, lines 102–161](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L102-L161)).
|
||||
Generated test-main dependencies are synthesized separately
|
||||
([lines 307–330](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L307-L330)).
|
||||
- Go's downstream action cache keys canonical package actions independently
|
||||
and consumes the already validated direct package imports, so visibility does
|
||||
not belong in action identity
|
||||
([`action.go`, lines 437–455](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L437-L455),
|
||||
[lines 628–657](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L628-L657)).
|
||||
|
||||
The focused native observer `internal_package_import_visibility` generates its
|
||||
lexical package/import tree under a temporary physical ancestor also named
|
||||
`internal`, while deliberate symlink destinations live outside that ancestor,
|
||||
so that unrelated-host-path case is exercised rather than documented only. It
|
||||
builds and runs allowed descendant, nested-final, `internalx`, and symlinked
|
||||
physical-owner cases; rejects outsider, sibling-prefix, nested-final, and
|
||||
symlink-escape cases at exact source positions with empty tool traces; maps an
|
||||
internal target symlinked to a differently shaped physical path back to its
|
||||
lexical owner's canonical directory; builds an internal package directly; and
|
||||
reverses requested allowed/forbidden product-descriptor order around one reused
|
||||
target. It checks ordinary, internal-test, and external-test
|
||||
source imports, generated-main transitive-export isolation, owner-only source
|
||||
order, direct export inputs, archive-only link closure, runtime results, warm
|
||||
no-op package production, rejection-state preservation, and the primary
|
||||
production chain's unit, export, assembly, object, archive, binary, and exact
|
||||
normalized tool arguments across independent cold Cstage and WWstage work
|
||||
roots. Test variants additionally compare their unit/export/archive bytes and
|
||||
exercise byte-equivalent runtime output in both stages.
|
||||
|
||||
## 12. Candidate architectures and hard-gate decision
|
||||
|
||||
Five candidates were developed as coherent systems, not as feature bins.
|
||||
|
||||
Reference in New Issue
Block a user