Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a2506e1
Begin work on IdentityCrossSign
martindale Aug 14, 2026
7f58ea2
Merge branch 'master' of github.com:FabricLabs/fabric into feature/rsi
martindale Aug 14, 2026
ab0acf7
Address security concerns, expand tests
martindale Aug 14, 2026
488a87d
Further refine identityCrossSign tests
martindale Aug 14, 2026
1fc6164
Add first-tier contract test
martindale Aug 14, 2026
9f2eb94
Improve Fabric chat
martindale Aug 14, 2026
0ed61d6
Add new helper functions, tests
martindale Aug 14, 2026
5557a2b
Expand fuzz tests
martindale Aug 14, 2026
4a1ff0a
Expand MuSig2 tests, various other BIP tests
martindale Aug 16, 2026
9306aba
Address collection and sync feedback
martindale Aug 16, 2026
f1b5e14
Test new scripts, fix various issues
martindale Aug 16, 2026
628f248
Update various examples
martindale Aug 16, 2026
9938917
Address production feedback
martindale Aug 16, 2026
ae7cce8
Begin message consolidation
martindale Aug 17, 2026
f98c8fa
Reduce file churn, update documentation
martindale Aug 17, 2026
bc03f89
Reduce changed files
martindale Aug 17, 2026
14d3d3a
Further reduction in changed files, minor fixes
martindale Aug 17, 2026
2a074a7
Resolve dependency errors
martindale Aug 17, 2026
9a8d6e8
General update of logs, documentation
martindale Aug 17, 2026
8273b7f
General docs updates, key security fixes
martindale Aug 17, 2026
8c4e789
General changelog update
martindale Aug 17, 2026
0b8ce4b
Various safety checks, logging expansion
martindale Aug 20, 2026
c51098d
Tighten various constraints
martindale Aug 20, 2026
4fd0e5c
Further tighten adversarial tests
martindale Aug 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Fabric Agents
See also [DEVELOPERS.md](DEVELOPERS.md) (repo layout, tests) and [docs/PRODUCTION.md](docs/PRODUCTION.md) (release gate).
See also [DEVELOPERS.md](DEVELOPERS.md) (repo layout, tests), [docs/PRODUCTION.md](docs/PRODUCTION.md) (release gate), and [docs/TYPES_AND_SERVICES.md](docs/TYPES_AND_SERVICES.md) (suite `types/` + `services/` layering vs http / Hub / Passport / GoonCitizen).

## Release posture
- **Target:** `0.1.0-RC1` reference client — not a production-hardened VM claim
Expand Down
2 changes: 1 addition & 1 deletion AUDIT.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ audit report.
| Peer misbehavior / scoring | Implemented (integrity, pin, session, contract ops, logical-register, nest cap, temp ban) — see [SECURITY.md](SECURITY.md) |
| P2P_RELAY amplification | Mitigated: bit-identical outer forward + nest depth cap + relay-as-is pin; gossip hop remains advisory |
| Chat mesh amplify | Mitigated: per-origin relay budget (`CHAT_MAX_RELAYS_*`) |
| Oversize wire frames | Mitigated: drop before parse/crypto (`HEADER_SIZE + MAX_MESSAGE_SIZE`) |
| Oversize / undersize wire frames | Mitigated: drop before parse/crypto (`< HEADER_SIZE` or `> HEADER_SIZE + MAX_MESSAGE_SIZE`); unparseable buffers drop without score/ban |
| Inventory HTLC address spoof | Mitigated: rebuild+match (`validateInventoryHtlcOffer`); AMP signer binding when present |
| Paid `/confirm` without L1 proof | Mitigated: fail-closed local verify or Hub `ConfirmInventoryHtlcPayment` (`cliDocumentExchange`) |
| Key reveal from hash echo | Mitigated: `authorizeDocumentKeyReveal` requires `settlementId`/`txid`; `forceReveal` opt-in only; inbound reveal requires key preimage + claim-after-open |
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
Recent changes to Fabric Core.

## 2026-08-14
- **RC1 first-tier contract:** `tests/rc1.first-tier.contract.js` locks the four production-readiness green domains (wire integrity, gossip/peering bounds, scoring/bans, identity/wallets) at the hostile-mesh bar. Peer drops **undersize** (`< HEADER_SIZE`) and unparseable frames before parse — truncated NOISE chunks are not body-hash mismatches and do not hard-ban.
- **IdentityCrossSign lift:** `functions/identityCrossSign.js`, `fabricIdentitySchnorr.js`, `identityCrossSignVerify.js` (+ `.d.ts`) are the canonical gossip strings and BIP340 helpers. HTTP site-login / device-link stay in `@fabric/http` and re-export these leaves. `signCrossSign` binds `localPubkey` to `fabricKey.pubkey` (raw HD `Key` and Passport `{ privateKeyHex, xpub }` round-trip). Canonical strings require compressed or x-only hex pubkeys (no `:` in fields); builders keep only a 64-hex nonce; `signCrossSign` rejects unknown `kind`. `fabricIdentityIdFromPubkeyHex` requires a compressed 66-hex public key. `.d.ts` files declare real arities / `ok` unions. `createdAt` is unsigned.
- **Peer dial storms:** `_fillPeerSlots` waits `PEER_CANDIDATE_RETRY_MS` (60s) before redialing the same candidate; refused TCP no longer constructs NOISE (shared handshake EventEmitter was leaking listeners). Transient `ECONNREFUSED` is recognized from the error message when Node omits `error.code`. `_connect` skips in-flight `_outboundDialTargets` so overlapping `connectTo` / reconnect cannot open duplicate sockets before `connections[target]` is set. Dial keys are canonical `host:port` (IPv6 bracketed), so `pubkey@host:port` cannot open a second TCP/NOISE session beside `host:port`. Candidate retry timestamps are pruned on queue eviction / expiry; `candidateRetryMs` must be finite and `> 0`. `_disconnect` and inbound encrypt-end / banned-static paths tear down NOISE. Outbound `connect` setup is try/caught so a handshake throw cannot leave the dial target stuck.
- **Wallet writes:** `_writeWalletDocument` uses a pid + random tmp suffix so concurrent writes in one process cannot clobber the same `.tmp`.
- **Peer `contract:message`:** `messageHex` is a getter so hot paths that ignore the wire hex skip `toBuffer()`.
- **Tests:** coverage for `--password=VALUE` (`functions/cliPasswordArgv`), GroupChange `signers.set` vote bind, wallet atomic write / touchWallet truncate, advertised vs verified peering suppress, Beacon persist-fail retain, `Environment.stop()` key wipe, and related lock/setup fail-closed paths.
- **Codacy (PR #183):** timing-safe setup password confirm; setup TUI treats cancel as a non-string password (no `== null`); hallmark hex length uses a literal class (no `new RegExp`); tier `when` paths skip `__proto__`/`constructor`/`prototype`; BIP65 lock constants avoid 32-bit hex literals; Semgrep/Opengrep exclude path-hardened `fabricSetup` / `environment` (containment already tested).
- **Shutdown / create:** `Environment.stop()` calls `lockWallet()` so seed/xprv/plaintext keys wipe even when the idle-lock handler was never installed; `touchWallet` creates a missing file with exclusive `wx` and does not truncate on `EEXIST`.
Expand Down
2 changes: 1 addition & 1 deletion DEVELOPERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Working from a **git checkout** (not the global package) is best when you are ch
## Repository layout
| Path | Role |
|------|------|
| `types/` | ES6 **classes** — `Actor`, `Peer`, `Service`, `Store`, `Message`, etc. CommonJS (`require`) throughout. |
| `types/` | ES6 **classes** — `Actor`, `Peer`, `Service`, `Store`, `Message`, etc. CommonJS (`require`) throughout. Cross-package homes: **[docs/TYPES_AND_SERVICES.md](docs/TYPES_AND_SERVICES.md)**. |
| `services/` | Long-running **integrations** (Bitcoin RPC, Lightning stubs, ZMQ, …) built on `Service`. |
| `contracts/` | Language snippets, traces, and tooling (e.g. type dependency graph). |
| `scripts/` | CLI entrypoints, doc helpers (`list-jsdoc-type-files.js`, `remove-legacy-types.sh`). |
Expand Down
6 changes: 6 additions & 0 deletions PUBLIC_API.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ Password-sealed JSON and in-memory lock sessions (CLI / setup wallets):
`@fabric/core/functions/sealedBlob`, `@fabric/core/functions/identityLock`
(ambient stubs `functions/sealedBlob.d.ts` / `functions/identityLock.d.ts`).

Protocol identity Schnorr + IdentityCrossSign (device-link gossip strings):
`@fabric/core/functions/fabricIdentitySchnorr`,
`@fabric/core/functions/identityCrossSign`,
`@fabric/core/functions/identityCrossSignVerify`. HTTP site-login / device-link
handlers stay in `@fabric/http` and re-export these leaves.

### Services

`@fabric/core/services/bitcoin`, `@fabric/core/services/lightning` — optional RPC
Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ Exact wire duplicates remain a silent drop (no score change). Wire-hash dedup re
`P2P_CHAT_MESSAGE` still emits locally, but mesh `relayFrom` is **per-origin rate-limited** (`CHAT_MAX_RELAYS_PER_ORIGIN_PER_MINUTE` / `settings.chat.maxRelaysPerOriginPerMinute`, default 30/min).

## Inbound frame size
Wire frames larger than `HEADER_SIZE + MAX_MESSAGE_SIZE` (override body via `settings.maxMessageSize`) are dropped **before** parse / body-hash / signature work.
Wire frames larger than `HEADER_SIZE + MAX_MESSAGE_SIZE` (override body via `settings.maxMessageSize`) **or shorter than `HEADER_SIZE`** are dropped **before** parse / body-hash / signature work. Unparseable buffers are dropped the same way (no score / ban). Truncated frames are not treated as body-hash mismatches — that would hard-ban a TCP peer for a partial NOISE chunk.

## Strict Protocol V1 (test contract)
Adversarial Peer coverage under the assumption that **NOISE payloads are raw, well-formed Fabric Messages** (not random bytes) lives in [`tests/protocol-v1/`](tests/protocol-v1/README.md): opcode × delivery matrix (`direct` / foreign `P2P_RELAY` / `P2P_FORWARD` peel), unknown-opcode policy (`UNKNOWN_MESSAGE` — must not alias to `P2P_BASE_MESSAGE`), multi-origin collusion budgets, and a typed live NOISE storm. Parser crash fuzz remains in `tests/fuzz/` and is **not** counted as semantic adversarial coverage.
Expand Down
6 changes: 6 additions & 0 deletions constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,11 @@ const PEERING_OFFER_MAX_RELAYS_PER_ORIGIN_PER_MINUTE = 60;
const PEERING_OFFER_MAX_PAYLOAD_CACHE = 50000;
/** Max queued connection candidates from {@link P2P_PEERING_OFFER} (FIFO eviction). */
const PEER_MAX_CANDIDATES_QUEUE = 128;
/**
* Minimum delay before {@link Peer#_fillPeerSlots} redials the same candidate.
* Immediate requeue plus `connections:close` was a tight ECONNREFUSED loop.
*/
const PEER_CANDIDATE_RETRY_MS = 60000;
/** Max wire-hash dedup entries in {@link Peer} (bounded memory). */
const PEER_MAX_WIRE_HASH_CACHE = 10000;
/**
Expand Down Expand Up @@ -430,6 +435,7 @@ module.exports = {
PEERING_OFFER_MAX_RELAYS_PER_ORIGIN_PER_MINUTE,
PEERING_OFFER_MAX_PAYLOAD_CACHE,
PEER_MAX_CANDIDATES_QUEUE,
PEER_CANDIDATE_RETRY_MS,
PEER_MAX_WIRE_HASH_CACHE,
PEER_MAX_LOGICAL_REGISTER_CACHE,
PEER_SCORE_BODY_HASH_MISMATCH_PENALTY,
Expand Down
16 changes: 10 additions & 6 deletions docs/OUTSTANDING.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
# Outstanding (security-first)
Living queue for this repo. Detail and closed items live in [SECURITY.md](../SECURITY.md) and [AUDIT.md](../AUDIT.md). Suite production march: [PRODUCTION_MARCH.md](PRODUCTION_MARCH.md).

**Last reviewed:** 2026-08-14. Codacy `500000000` rewritten as `Number('500000000')`; genesis journal cap and publish-author fail-closed on existing files.
**Last reviewed:** 2026-08-14. [#185](https://github.com/FabricLabs/fabric/pull/185) + RC1 first-tier contract (`tests/rc1.first-tier.contract.js`; undersize-frame drop).

## Blockers before shared-host / non-experimental tag
1. **Third-party review** of `types/peer.js`, inventory HTLC, sealed exchange, `publishedDocumentEnvelope` ([AUDIT.md](../AUDIT.md) recommendations).
2. **Do not claim** a hardened contract VM — `Machine.define` still binds host JS ([PUBLIC_API.md](../PUBLIC_API.md)).
3. Downstream **site-login / device-link redeem** is not a core bug; Hub/`@fabric/http` still treat QR `sessionId` as the capability. Tracked in those repos.

## Next slices (this repo)
- [ ] **IdentityCrossSign lift (local, not #183)** — `functions/identityCrossSign.js`, `fabricIdentitySchnorr.js`, `identityCrossSignVerify.js` + tests exist on disk. Held off [#183](https://github.com/FabricLabs/fabric/pull/183) (CodeRabbit ~150-file cap). Do **not** commit working-tree `package.json` / `PUBLIC_API.md` / `AGENTS.md` pointers until that follow-up PR (smoke would require missing leaves). Pin/link core before Hub/http/Passport/GoonCitizen re-exports CI.
- [ ] Type-tree keep/remove lock in [PRODUCTION_MARCH.md](PRODUCTION_MARCH.md) (`Scribe` / `Reader` / Global docs clutter).
- [ ] Eager `messageHex` laziness on Peer hot paths (performance, not a correctness claim).
- [ ] Type-tree keep/remove lock in [PRODUCTION_MARCH.md](PRODUCTION_MARCH.md) (inventory remaining classes; `Scribe`/`Reader` deprecation notes are in).
- [ ] Coordinated `contractId` → `contractIdentifier` rename.
- [ ] Hub / Passport callers still hard-coding BIP44 **7778** on mainnet should use `fabricIdentityDerivationPath(…, network)` (**7777** mainnet / **7778** otherwise).
- [ ] Hub / Passport callers still hard-coding BIP44 **7778** on mainnet should use `fabricIdentityDerivationPath(…, network)` (**7777** mainnet / **7778** otherwise). Do not silently re-derive existing Hub identities.
- [ ] Blinded-execution remains a **scaffold** (not Yao GC) even with signed `at`.
- [ ] Keep `.codacy.yml` Semgrep/Opengrep exclusions for `functions/fabricSetup.js` and `types/environment.js` unless a replacement SAST job covers those path-construction helpers (CodeRabbit asked to drop the excludes; Codacy still ignores `nosemgrep`).

## Closed this pass (do not re-open)
- Undersize AMP frames (`< HEADER_SIZE`) and unparseable buffers drop before parse/crypto (no score / ban). Oversized already did. Locked in `tests/rc1.first-tier.contract.js` with the other first-tier RC1 invariants (hop=0 does not poison gossip cache; BASE_MESSAGE cannot inject gossip; budget is TCP-origin keyed; score-0 still disconnects; sealed wallet public object omits seed/xprv).
- IdentityCrossSign / identity Schnorr / verify lifted into `functions/` after [#183](https://github.com/FabricLabs/fabric/pull/183) merge (was held for the CodeRabbit file cap).
- `signCrossSign` localPubkey is the Fabric signing pubkey (not Bech32 `id` / HD master). Canonical cross-sign pubkeys are compressed or x-only hex; unknown `kind` is rejected. `fabricIdentityIdFromPubkeyHex` requires compressed 66-hex (no truncated `Buffer.from(..., 'hex')`). `createdAt` is unsigned display metadata. `.d.ts` files declare real arities / `ok` unions.
- `_fillPeerSlots` candidate retry cooldown + NOISE-after-TCP-connect (playnet `:7778` ECONNREFUSED / MaxListeners storm). `_connect` also skips in-flight `_outboundDialTargets`. Dial keys are canonical `host:port` so `pubkey@host:port` cannot duplicate `host:port`. `_candidateRetryAt` is pruned; `_disconnect` and inbound encrypt-end / banned-static paths tear down NOISE; outbound connect setup is try/caught.
- Wallet tmp files use `pid` + random suffix; Environment tests share `tests/helpers/isolatedHome.js`.
- `contract:message` `messageHex` is lazy (getter). `Reader` is `@deprecated` (fold into Peer/Message ingest).
- Blinded-execution `at` bind; Beacon `ready` finalize; peering self-suppress via verified AMP signer; empty `signers: []` spend-key widen; Beacon ARC authority walk.
- Gossip-network `P2P_PEERING_OFFER` candidate expect includes AMP `verifiedPubkey` (`tests/fabric.peer.gossip-network.js`).
- Codacy `no-loss-of-precision` on `functions/contractTaproot.js` `CLTV_TIMESTAMP_THRESHOLD` — use `Number('500000000')` (decimal and `5e8` both trip the PR check).
Expand All @@ -26,4 +30,4 @@ Living queue for this repo. Detail and closed items live in [SECURITY.md](../SEC
- `printGeneratedWallet` never prints the master xprv (`FABRIC_DEBUG` included). Plaintext restore validates encryption password before `setWallet`.

## PRs
[#183](https://github.com/FabricLabs/fabric/pull/183) — mocha + codecov green at `4d7351ee3`; remaining GitHub check was Codacy (`500000000` literal). Cursor review on `4d7351ee3` reports **no remaining High/Medium/Critical**. Still deferred: IdentityCrossSign lift (file cap); `sealedBlob`/`identityLock` `.d.ts` stubs (new files); RFC6902 multi-op JSON bridge (http); eager `messageHex`; `withIsolatedHome` test helper; wallet tmp-name random suffix; `.codacy.yml` Semgrep excludes stay until a replacement SAST job exists.
[#185](https://github.com/FabricLabs/fabric/pull/185) — WIP ARC polish on `feature/rsi` after [#183](https://github.com/FabricLabs/fabric/pull/183) merge. CI green on `488a87da1`. Bugbot Highs (wrong cross-sign pubkey; duplicate outbound dials) addressed; `pubkey@host:port` now canonicalizes onto the same dial slot. Still deferred: RFC6902 multi-op JSON bridge (http); `.codacy.yml` Semgrep excludes stay until a replacement SAST job exists; docstring-coverage gate; PR title.
3 changes: 2 additions & 1 deletion docs/PRODUCTION_MARCH.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Related docs:
- `docs/PRODUCTION.md`
- `docs/RELEASE_CHECKLIST.md`
- `docs/OUTSTANDING.md` — **security-first queue** (this repo)
- `docs/TYPES_AND_SERVICES.md` — cross-package `types/` + `services/` homes (http / Hub / Passport / GoonCitizen)
- `SECURITY.md` / `AUDIT.md`
- `AGENTS.md`

Expand Down Expand Up @@ -84,7 +85,7 @@ Rationale:

### Step B: Fast reductions

- [ ] Mark `Scribe` and `Reader` with explicit deprecation notes in code comments/docs.
- [x] Mark `Scribe` and `Reader` with explicit deprecation notes in code comments/docs.
- [ ] Stop advertising non-core classes in onboarding docs/examples.
- [ ] Keep runtime compatibility for one release cycle through aliasing only where needed.

Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ One-off reports and analysis files in the repo root are listed in **[NON_CANONIC

## Downstream

**hub.fabric.pub** (rendezvous hub, HTTP bridge) and **@fabric/http** are separate repos; align versions per **[docs/PRODUCTION.md](PRODUCTION.md)** and **[../DEVELOPERS.md](../DEVELOPERS.md)**.
**hub.fabric.pub** (rendezvous hub, HTTP bridge) and **@fabric/http** are separate repos; align versions per **[docs/PRODUCTION.md](PRODUCTION.md)** and **[../DEVELOPERS.md](../DEVELOPERS.md)**. Cross-package `types/` + `services/` ownership (including Passport and GoonCitizen): **[TYPES_AND_SERVICES.md](TYPES_AND_SERVICES.md)**.
Loading
Loading