Phase 0: productionize build pipeline and bring workspace to green#10
Merged
iduartgomez merged 3 commits intomainfrom Apr 9, 2026
Merged
Phase 0: productionize build pipeline and bring workspace to green#10iduartgomez merged 3 commits intomainfrom
iduartgomez merged 3 commits intomainfrom
Conversation
…2024 Groundwork to bring freenet-email toward production readiness: - Bump freenet-stdlib 0.3.2 → 0.3.5 across workspace - Port full web-container contract from freenet-river: ed25519 signature verification, version monotonicity, state delta, 6 unit tests (replaces 40-line stub) - Add freenet-email-core::web_container::WebContainerMetadata - Fix inbox contract host test: use 2048-bit RSA key (was 32-bit, panicked on SHA256 sign); add rsa std dev-dep to re-enable OsRng - Feature-gate ContractInterface dead-code warnings in inbox crate - Silence unexpected_cfgs in identity-management (freenet-stdlib #[delegate] macro emits cfg(feature = "trace") without declaring it) - Migrate workspace to Rust edition 2024 - Clippy pass: ~44 auto-fixes (clone_on_copy, needless_borrow, repeat_n, get_first, manual_inspect, collapsible_if) plus targeted #[allow(dead_code)] and #[allow(clippy::arc_with_non_send_sync)] with comments explaining the wasm single-threaded rationale - Remove unreachable identities delegate response arm in api.rs (shadowed by earlier ApplicationMessage arm; flagged for Phase 1) Note: UI still fails to build because include_bytes!/include_str! targets for token-allocation-record and token-generator don't exist yet. Those crates are vendored in the next commit.
…-core These crates host the anti-flood-token contract and delegate but were only present as empty build/ placeholders in freenet-email. The UI references their compiled WASM and code-hash files via include_bytes! and include_str!, so the UI has been unable to compile since the monorepo extraction. Copied wholesale from freenet-core/modules/antiflood-tokens/, with minimal adjustments for this workspace: - Added both crates as workspace members in root Cargo.toml - Dropped `freenet-main-contract` / `freenet-main-delegate` from their default features. Those feature gates control whether the #[contract] and #[delegate] macros emit the extern "C" FFI wrapper, which is only valid when targeting wasm32 (it references WasmLinearMem and other host-incompatible memory layouts). `fdev build` will enable them explicitly when producing the WASM artifacts. - Added module-level #[cfg_attr(not(feature = "freenet-main-delegate"), allow(dead_code))] to token-generator so host builds don't warn about the gated-off helper functions, matching the inbox crate pattern. Both crates now build cleanly under `cargo check --workspace` on the host target. The UI still won't compile until task #4 wires up `fdev build` to produce the WASM artifacts and code hash files that ui/src/aft.rs and ui/src/api.rs include via include_bytes!/include_str!.
Completes Phase 0 task #4: the workspace now builds end-to-end without manual fixup. `cargo check --workspace`, `cargo clippy --workspace --all-targets`, and `cargo test --workspace` all pass (17 tests passing, 1 legacy integration test ignored pending a fixture regeneration story). Makefile.toml ------------- Add five cargo-make tasks that drive `fdev build` + `fdev inspect` for each contract/delegate, writing WASM to the modules/.../build/freenet paths the UI embeds via include_bytes!, and extracting code hashes into the *_code_hash text files the UI embeds via include_str!: - build-inbox-contract - build-token-allocation-record - build-token-generator - build-identity-management-delegate - generate-identity-params Plus a meta target `build-contracts` that runs all five as dependencies, now wired into build-ui and dev. Each task sets CARGO_TARGET_DIR explicitly to work around fdev 0.3.200 panicking in get_workspace_target_dir() when its compile-time CARGO_MANIFEST_DIR no longer exists. ui/build.rs (new) ----------------- Fail-fast verifier that checks all eight include_bytes!/include_str! target files exist and are non-empty before rustc tries to compile src/aft.rs and src/api.rs. On failure, prints a structured error listing each missing artifact, a human description, and the exact cargo-make target that produces it. Converts a cryptic rustc "couldn't read" into an actionable message. test-contract/identity/ ----------------------- Committed EC P-384 test keypair for the identity-management delegate, so `cargo make generate-identity-params` is deterministic across clones and CI runs. README.md documents the security implications: - The key is a TEST-ONLY identity. Anyone with read access can impersonate this identity, which is acceptable because the repo is public anyway and the key carries no user data or production authority. - Production deployments must generate their own keypair out of band. Same pattern as freenet-river's `test-contract/test-keys.toml`. Small fixes uncovered along the way ----------------------------------- - token-generator/src/tests.rs: rename `gen` to `gen_` (reserved keyword under edition 2024). - token-allocation-record/tests/test.rs: #[ignore] the legacy integration test, which requires a build/freenet/contract-state fixture that doesn't exist in this tree (it lived in the upstream antiflood-tokens test harness). TODO left in place. .claude/settings.json: enable the Freenet agent-skills marketplace plugin so future contributors get the same review/build tooling.
iduartgomez
added a commit
to freenet/freenet-core
that referenced
this pull request
Apr 9, 2026
These crates have been moved to the freenet-email repository, which is their only consumer (see freenet/mail#10). They were never part of this workspace's `members` list — they lived in modules/ as orphaned, independently-built crates referenced only by freenet-email's legacy Makefile. Removed: modules/antiflood-tokens/ (contracts/token-allocation-record, delegates/token-generator, interfaces, and the standalone Makefile/workspace) modules/identity-management/ (delegate, tool binary, Makefile) Verified: `cargo check --workspace` compiles 236 crates clean from this state — no dangling references anywhere in freenet-core.
Merged
2 tasks
iduartgomez
added a commit
that referenced
this pull request
Apr 9, 2026
Replaces the broken `ui-testing` feature flag (which referenced an
`Identity { description }` field that no longer existed and called a
nonexistent `InboxController::load_messages`) with two orthogonal flags
matching the freenet-river pattern:
- `example-data` seeds the UI with mock identities and 2-3 mock
messages per identity so the inbox renders with no real state.
- `no-sync` skips the local-node WebSocket entirely.
`cargo make dev-example` (also new) runs the full offline preview from
a clean clone with zero contract artifacts:
dx serve --features example-data,no-sync --no-default-features
Wiring details:
- The sync coroutine in app.rs is now gated on
`all(use-node, not(no-sync))`. The fallback branch is reused for
both `not(use-node)` and `no-sync`.
- `INBOX_CODE_HASH`, `TOKEN_RECORD_CODE_HASH`, and
`TOKEN_GENERATOR_DELEGATE_CODE_HASH` collapse to empty string
placeholders under `not(use-node)`. They're only dereferenced from
contract-bridge code paths that are themselves dead in offline
mode, so the fallback values are never observed.
- `ui/build.rs` short-circuits to `return` when `CARGO_FEATURE_NO_SYNC`
is set or `CARGO_FEATURE_USE_NODE` is unset, so the fail-fast
artifact check from PR #10 doesn't bloc the offline build.
- A crate-level
`cfg_attr(not(use-node), allow(dead_code, unused_imports, ...))`
suppresses the swathe of dead-code lints triggered when the
contract-bridge half of `inbox.rs` / `aft.rs` / `api.rs` is
unreachable. The default `use-node` build remains the source of
truth for clippy and stays warning-clean.
- `build-ui-example-no-sync` cargo-make target added for CI/Playwright
release builds (Phase 3).
Drive-by cleanup of three pre-existing wasm32-target warnings that the
host-target workspace check missed:
- `pk` unused variable in `contracts/inbox/src/lib.rs::add_message`
(the surrounding `match` was a no-op debug stub).
- `StreamExt` unused import in `ui/src/api.rs::WebApi::new`.
- `mut api` no longer needs to be mutable in the same function.
Verification:
cargo check --workspace --all-targets — clean
cargo clippy --workspace --all-targets -- -D warnings — clean
cargo check -p freenet-email-ui \
--no-default-features --features example-data,no-sync \
--target wasm32-unknown-unknown — clean
cargo clippy -p freenet-email-ui (same flags) -- -D warnings — clean
Part of #5.
6 tasks
iduartgomez
added a commit
that referenced
this pull request
Apr 9, 2026
…, deser hardening (#11) * feat(ui): offline dev loop via example-data + no-sync features Replaces the broken `ui-testing` feature flag (which referenced an `Identity { description }` field that no longer existed and called a nonexistent `InboxController::load_messages`) with two orthogonal flags matching the freenet-river pattern: - `example-data` seeds the UI with mock identities and 2-3 mock messages per identity so the inbox renders with no real state. - `no-sync` skips the local-node WebSocket entirely. `cargo make dev-example` (also new) runs the full offline preview from a clean clone with zero contract artifacts: dx serve --features example-data,no-sync --no-default-features Wiring details: - The sync coroutine in app.rs is now gated on `all(use-node, not(no-sync))`. The fallback branch is reused for both `not(use-node)` and `no-sync`. - `INBOX_CODE_HASH`, `TOKEN_RECORD_CODE_HASH`, and `TOKEN_GENERATOR_DELEGATE_CODE_HASH` collapse to empty string placeholders under `not(use-node)`. They're only dereferenced from contract-bridge code paths that are themselves dead in offline mode, so the fallback values are never observed. - `ui/build.rs` short-circuits to `return` when `CARGO_FEATURE_NO_SYNC` is set or `CARGO_FEATURE_USE_NODE` is unset, so the fail-fast artifact check from PR #10 doesn't bloc the offline build. - A crate-level `cfg_attr(not(use-node), allow(dead_code, unused_imports, ...))` suppresses the swathe of dead-code lints triggered when the contract-bridge half of `inbox.rs` / `aft.rs` / `api.rs` is unreachable. The default `use-node` build remains the source of truth for clippy and stays warning-clean. - `build-ui-example-no-sync` cargo-make target added for CI/Playwright release builds (Phase 3). Drive-by cleanup of three pre-existing wasm32-target warnings that the host-target workspace check missed: - `pk` unused variable in `contracts/inbox/src/lib.rs::add_message` (the surrounding `match` was a no-op debug stub). - `StreamExt` unused import in `ui/src/api.rs::WebApi::new`. - `mut api` no longer needs to be mutable in the same function. Verification: cargo check --workspace --all-targets — clean cargo clippy --workspace --all-targets -- -D warnings — clean cargo check -p freenet-email-ui \ --no-default-features --features example-data,no-sync \ --target wasm32-unknown-unknown — clean cargo clippy -p freenet-email-ui (same flags) -- -D warnings — clean Part of #5. * test(inbox): integration tests for ContractInterface round trip Adds the first real integration test coverage for the inbox contract, running native Rust against the `--features contract` build (no wasm FFI). Seven tests across validation, update, and summary/delta: validate_state: - validate_accepts_signed_empty_inbox - validate_rejects_tampered_last_update (documents current behavior — `last_update` is not part of the signed payload, so the validator currently accepts the change. The test exists to surface this fact and to fail loudly if the contract is hardened later.) - validate_rejects_wrong_owner_signature update_state (AddMessages flow): - update_accepts_add_message_with_valid_token (full path: signed token + matching TokenAllocationRecord supplied via `UpdateData::RelatedState`) - update_rejects_message_with_unknown_token_record (asserts `requires(...)` rather than silent acceptance) - update_rejects_token_with_invalid_slot (Tier::Min1 + non-zero second → trips `is_valid_slot`) summarize_state / get_state_delta: - summarize_then_delta_yields_only_new_messages The tests live under `contracts/inbox/tests/` (a new directory). All crypto + state-construction scaffolding is centralized in `tests/common/mod.rs`: - `make_keypair` — fresh 2048-bit RSA pair - `make_params` — serialize InboxParams to Parameters - `make_inbox_state` — build a signed Inbox JSON payload (the public `Inbox::new` is gated behind `wasmbind`, so we hand-roll the wire format and call `SigningKey::sign` on the fixed STATE_UPDATE salt directly) - `make_inbox_value` — same, but returns the JSON value so a caller can tamper with one field before re-serializing - `make_token_assignment` — sign (tier, slot, hash) per the TokenAssignment::signature_content contract documented on the type - `make_message`, `make_token_record`, `related_contracts_with`, `add_messages_delta`, `related_state_update`, `assignment_hash_for`, `token_record_id_for`, `fixed_valid_slot` Also adds a `cargo make test-inbox` target that runs just the new integration suite (`-p freenet-email-inbox --features contract --test integration`) for fast iteration on contract changes. Verification: cargo make test-inbox — 7/7 pass cargo clippy -p freenet-email-inbox --features contract \ --tests -- -D warnings — clean Part of #5. * fix(deser): harden identity-management deserialization boundaries Two `serde_json::from_slice(...).unwrap()` calls in the `identity-management` delegate's `TryFrom<&[u8]>` impls would have panicked the delegate process on a malformed payload from the network. Both now propagate `DelegateError::Deser`. - `IdentityManagement::try_from(&[u8])` (lib.rs:107) - `IdentityMsg::try_from(&[u8])` (lib.rs:208) Adds a `boundary_tests` module with four regression tests that feed garbage / truncated bytes through both `TryFrom` impls and assert `Err(DelegateError::Deser(_))`. Also adds parallel boundary regression tests in `freenet-aft-interface` (`modules/antiflood-tokens/interfaces`). The audit cited in #5 named "~50 chrono unwraps" in this file as the target, but inspection shows all of them sit on hardcoded constants (tier durations, hardcoded date constants in `get_date`) or post-check arithmetic — none touch network input. The actual network boundaries are the `TryFrom<&[u8]>` / `TryFrom<Parameters>` / `TryFrom<StateDelta>` impls, all of which already returned `Result`. The new tests pin that fact (`malformed_*`, `truncated_*`, `empty_*`) so any future regression that swaps a `?` for an `unwrap` trips them. Coverage: modules/identity-management: 4 new tests modules/antiflood-tokens/interfaces: 7 new tests Verification: cargo test -p identity-management — 4 passed cargo test -p freenet-aft-interface — 13 passed (6 pre-existing + 7 new) Part of #5.
6 tasks
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.
Summary
Phase 0 of the productionization plan. Brings the extracted
freenet-emailrepo from the broken state it was left in after the monorepo split to a fully-buildable workspace with cleancheck,clippy, andtest.Three commits, progressively layered:
4b85d15) — bumpfreenet-stdlib0.3.2→0.3.5, port the full web-container contract fromfreenet-river(with ed25519 signature verification, version monotonicity, and 6 unit tests), fix the inbox contract host test (RSA key size + rand), migrate the workspace to Rust edition 2024, and clean ~44 clippy warnings.158ceb5) — copytoken-allocation-recordandtoken-generatorfromfreenet-core/modules/antiflood-tokens/into this repo. They existed only as 0-bytebuild/placeholders before, which meant the UI has been uncompilable since the monorepo extraction. Also dropsfreenet-main-contract/freenet-main-delegatefrom default features (the#[contract]/#[delegate]macros expand to wasm-only FFI wrappers that break host builds), matching howidentity-managementis structured.adc47b7) —cargo make build-contractsnow drivesfdev build+fdev inspectto produce all 4 WASM artifacts and 3*_code_hashfiles the UI embeds viainclude_bytes!/include_str!. A newui/build.rsfail-fast checker verifies all 8 artifacts exist before rustc tries to compile the includes, converting cryptic "couldn't read" errors into a structured list of missing files and thecargo maketarget that produces each one. Also commits a TEST-ONLY EC P-384 keypair undertest-contract/identity/with a security-warning README, matching thefreenet-riverpattern for reproducible delegate builds.Status on a clean checkout:
Notable design decisions
Test plan
Follow-ups