feat(icons): deny the network by default, and give the cache a way to be filled - #454
Merged
Merged
Conversation
… be filled Closes #440. #320 gated Google Fonts: a family missing from the cache is refused by name, with the URL that was not called, and one global flag opts in. Icons had nothing. `icon_source_cache` reached api.iconify.design on any miss, from `validate`, `still`, `sheet` and every encoder, with no opt-in and no way to say that a render must not touch the network. `RemoteIconPolicy` mirrors `RemoteFontPolicy`, down to the atomic and the refusal naming the icon, the URL and the file to drop an SVG into. The flag is its own, `--allow-remote-icons`, rather than a shared `--allow-remote-fonts` or an umbrella. Widening an existing flag grants consent retroactively: a CI job passing `--allow-remote-fonts` today consented to fonts.googleapis.com, not to a second host a scenario names. Each flag names its own target. A deny with no way to fill the cache is a deny with no way out, so `rustmotion icons prefetch -f <scenario>` downloads what a scenario names, and `icons check` reports what is missing without fetching. `prefetch` takes no flag — running it is the opt-in. Both reuse the walk `preload.rs` already had, extracted as `collect_icon_requests`. The gate sits after the cache read AND after the pre-#425 name migration, so a cache filled under the old `{slug}-{colour}-{w}x{h}.svg` naming still resolves offline. Refusing the network must not break a render that already has what it needs; a test pins that specifically. `IconsUnresolved` stopped advising "connect once" and names the prefetch command instead.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #440.
#320 gated Google Fonts: a family missing from the cache is refused by name, with the URL that was not called and the directory to drop a TTF into, and one global flag opts in. Icons had nothing —
icon_source_cachereachedapi.iconify.designon any miss, fromvalidate,still,sheetand every encoder, with no opt-in and no way to say "this render must not touch the network".The gate
RemoteIconPolicymirrorsRemoteFontPolicy, down to the atomic and the shape of the refusal:Its own flag, not a shared one. The issue left this open, and the argument that settles it is consent: widening
--allow-remote-fontsto cover icons grants it retroactively. A CI job passing that flag today consented tofonts.googleapis.com, not to a second host that a scenario gets to name. Two flags, each naming its own target, is the version that can be explained honestly. An umbrella--allow-networkcan be added later on top of both; it cannot be subtracted.Where it sits matters. After the cache read, and after the pre-#425 legacy name migration. A cache filled under the old
{slug}-{colour}-{w}x{h}.svgnaming still resolves offline, because refusing the network must not break a render that already has what it needs. There is a test for exactly that, since it is the one placement mistake that would look fine in review.The way to fill the cache
A deny-by-default with no prefetch turns an offline CI runner into a manual copy of SVGs — which is what #320's
cache_hintalready asks of it for fonts, and the issue called that out as the piece that makes the first one usable.prefetchtakes no flag: running it is the opt-in. Both subcommands reuse the walkpreload.rsalready performed, extracted ascollect_icon_requestsrather than written a second time.--quietmakescheckprint one missing icon per line and nothing else, so it composes in a shell.Verified end to end
On a scenario naming two icons absent from the cache, in this order:
icons check→2 icon(s) named, 0 already cached, both listedstillwithout the flag → refused, naming the icon, the URL, both ways out and the exact pathicons prefetch→Fetched 2 icon(s)still, still without the flag → renders, both icons painted in their own coloursicons check→Nothing to fetch — this scenario renders offline.Four tests, each verified to fail when its own fix is reverted.
cargo fmt --all --check,cargo clippy --workspace --all-targets --features rustmotion/studio -- -D warnings, andcargo test --workspace --features rustmotion/studio(2132 tests) pass.Also
IconsUnresolvedadvised "connect once so they are downloaded" — stale as soon as the gate exists, since connecting is precisely what is now refused. It names the prefetch command instead.Documented in
CLAUDE.mdnext to the font gate, and in the README's CLI reference.