fuzz: adopt fuzzing (wave 1) + alkcall 0.8.1 bump
Bump the substrate dependency to alkcall 0.8.1 — the bug-fix release
whose fix (duplicate adopt/open no longer destroying the live channel)
is directly relevant to this crate's reverse-path adopt flow.
Adopt fuzzing per docs/research/fuzzing.md, scoped smaller than
alkcall's (the envelope/chunk/demux/manager surfaces are upstream and
now fuzzed there; this crate fuzzes its own named downstream target —
the ADR-003 datagram codec — plus the params/reply parsers):
- fuzz/ workspace per the alkcall pattern: nightly-pinned subtree
(rust-toolchain.toml), thin fuzz_target! binaries, and a
stable-toolchain shared crate carrying the invariant logic so the
committed corpus replays as plain `cargo test` (the fuzz gate in
the release checklist — no hosted CI, alkcall §7.9 posture).
- Targets (both over already-pub APIs; no #[cfg(fuzzing)] exposure):
- datagram_codec — DatagramReader::feed + frame_datagram: no-panic,
infallible decode, size bound, F-2 sentinel layering (empty
datagram only from a length-0 header at a frame boundary),
3-byte-slice splitting transparency, re-frame round-trip,
oversize rejection at the bound, is_mid_datagram framing state,
and the decoder-state retained-bytes bound.
- params_parse — serde params/reply parsers + establishment_reason:
no-panic on raw bytes and bounded structured Values, clean typed
failure, round-trips, listen: 0 pin, loud/lenient projection-pair
agreement, pass-through reason extraction model.
- New public diagnostic: DatagramReader::retained_bytes() (decoder-
state byte count; the fuzz bound asserts against it).
- 96 committed seeds (gen_fuzz_seeds.py) + the campaign-found crash
input promoted as datagram_codec/seed-900; grown corpora gitignored.
- run-detached.sh: setsid+nohup runner so campaigns never share fate
with the agent session process tree (fuzzing.md §5).
Campaign findings this session were harness-model defects, not crate
bugs (both invisible to example-based review; the alkcall
"fuzzer as harness-checker" pattern confirmed):
- the F-2 empty-datagram invariant first counted [00 00] pairs in the
raw stream — a pair inside a payload region is payload, not a
header; corrected to walk the framing (crash artifact saved).
- establishment_reason is a pass-through extractor of details.reason,
not a validated table (harness first asserted a closed set).
- is_mid_datagram means a partial datagram, not buffered header bytes
(a 1-byte header fragment is buffered, not in flight).
Verification: cargo test 135 passed; clippy -D warnings and fmt clean
(main + fuzz/shared); corpus replay green; cargo fuzz build clean;
wasm32-unknown-unknown check clean. Wave-1 campaigns (10-min detached,
fork mode): params_parse 3.14M execs / datagram_codec 827k execs,
0 crashes/OOMs/timeouts; coverage saturated on the codec state space.
This commit is contained in:
1 parent
d789031863
commit
57285d23bd
116 files changed
+2662
-4
No files matched your search
Generated
+2
-2
@@ -27,9 +27,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alkcall"
|
||||
version = "0.8.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8695d47cee5b5a5fe68471f04a505bc257a7e7ed9e64d827de33ff83adf4db12"
|
||||
checksum = "bf6af1e4af1460480849adf959c972d65deeafc36f4101064ced1ce6d1adfd5b"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
|
||||
+6
-2
@@ -9,7 +9,11 @@ repository = "https://git.alk.dev/alkdev/alktunnels"
|
||||
readme = "README.md"
|
||||
keywords = ["tunnel", "proxy", "channels", "alkcall", "network"]
|
||||
categories = ["network-programming", "asynchronous"]
|
||||
exclude = [".opencode/", "AGENTS.md", "docs/reviews/", "docs/research/", "docs/plans/", "tasks/", "docs/sdd_process.md"]
|
||||
exclude = [".opencode/", "AGENTS.md", "docs/reviews/", "docs/research/", "docs/plans/", "tasks/", "docs/sdd_process.md", "fuzz/"]
|
||||
|
||||
[workspace]
|
||||
members = ["."]
|
||||
exclude = ["fuzz"]
|
||||
|
||||
[lib]
|
||||
name = "alktunnels"
|
||||
@@ -19,7 +23,7 @@ default = []
|
||||
local = ["tokio/net"]
|
||||
|
||||
[dependencies]
|
||||
alkcall = "0.8.0"
|
||||
alkcall = "0.8.1"
|
||||
tokio = { version = "1", default-features = false, features = ["rt", "sync", "io-util", "macros", "time"] }
|
||||
bytes = "1"
|
||||
futures = "0.3"
|
||||
|
||||
@@ -0,0 +1,415 @@
|
||||
# Fuzzing alktunnels: Proposal and Plan
|
||||
|
||||
**Status:** adopted — wave-1 complete (`datagram_codec` +
|
||||
`params_parse` implemented, seeds committed, two 10-min campaigns
|
||||
clean, two harness-model findings fixed — see §7); wave-2 (stateful
|
||||
two-pump target) deferred, see §4. Campaigns run via the detached
|
||||
runner (§6) — **never as a foreground child of an agent session** (§5).
|
||||
**Date:** 2026-09-28
|
||||
**Upstream precedent:** `/workspace/@alkdev/alkcall/docs/research/fuzzing.md`
|
||||
(0.8.0 — 0.8.1 campaign; one real finding: duplicate adopt/open destroying
|
||||
the live channel, fixed in 0.8.1). Tooling, corpus policy, runner, and the
|
||||
no-hosted-CI posture are inherited from that doc wholesale — this doc does
|
||||
not re-litigate them; it scopes them to this crate.
|
||||
|
||||
---
|
||||
|
||||
## 1. Should this crate be fuzzed?
|
||||
|
||||
**Yes — but scoped smaller than alkcall's.** The decision follows from
|
||||
three lines, all pointing the same way:
|
||||
|
||||
1. **alkcall's fuzz doc already assigned this to us.** Its §5
|
||||
"non-surfaces (deliberately)" note ends: *the channels layer carries
|
||||
opaque `Bytes` and the handler owns sub-stream framing (ADR-035) —
|
||||
those downstream parsers are downstream crates' fuzz targets.* Our
|
||||
`wire.rs` datagram codec IS that named downstream target. Fuzzing it
|
||||
completes alkcall's fuzz scope rather than duplicating it.
|
||||
|
||||
2. **We own one hand-rolled parse surface of exactly the covered class.**
|
||||
`DatagramReader::feed` (`src/wire.rs:100`) is an incremental
|
||||
length-prefix state machine reassembling `[len: u16 BE][payload]`
|
||||
frames across arbitrary chunk boundaries — length arithmetic and
|
||||
boundary handling, the dominant rust-fuzz trophy-case classes. It is
|
||||
sync, pure, allocation-light, and infallible **by contract** (the
|
||||
decode direction cannot fail; oversize is rejected at frame time) —
|
||||
a fuzz target is how that contract is *demonstrated* rather than
|
||||
believed.
|
||||
|
||||
3. **The stateful DoS class applies to us directly.** One pre-fuzz
|
||||
code-review candidate, the analog of alkcall §6.2-1 (the
|
||||
early-arrival key-space): `DatagramHalves.pending`
|
||||
(`src/consumer.rs:78`) queues every datagram decoded from a chunk
|
||||
beyond the one returned to the caller. A single 16 MiB chunk of
|
||||
`[00 00]` pairs = ~8.4 M empty datagrams → ~8.4 M `VecDeque`
|
||||
entries (≈ 400+ MiB) from ONE peer chunk — a ~25–50× memory
|
||||
amplification riding a bounded channel buffer. Example-based tests
|
||||
structurally cannot find this; a byte-sequence target with a
|
||||
pending-bytes assertion will.
|
||||
|
||||
**The honest caveat** (mirroring alkcall §1): the highest-value alkcall
|
||||
targets — envelope framing, chunk header, demux, manager — are upstream
|
||||
and now fuzzed (0.8.1). Our params parsing is serde + registry-side
|
||||
jsonschema (upstream's `spec_parse` target covers attacker-shaped
|
||||
schemas compiling at registration). Expected yield here: datagram-codec
|
||||
pathologies, the pending-queue bound (§1.3), serde/untagged-enum edge
|
||||
cases in params, and lifecycle invariants in the two-pump shape. That
|
||||
is worthwhile, not five-targets-worth of new machinery on day one —
|
||||
hence the two-wave scope in §4. If the first campaigns find nothing,
|
||||
that is the successful-negative-result posture alkcall's §1 codified:
|
||||
"we think the codec is robust" becomes a demonstrated property, and the
|
||||
targets become regression protection for a wire-stable format
|
||||
(ADR-003).
|
||||
|
||||
## 2. Toolchain (inherited, not re-decided)
|
||||
|
||||
Identical to alkcall §4: **cargo-fuzz 0.13.2 + `arbitrary` 1.4.x**,
|
||||
nightly confined to the `fuzz/` subtree via `fuzz/rust-toolchain.toml`,
|
||||
the crate itself stays stable at MSRV 1.88. AFL optional/deferred;
|
||||
bolero deferred (same async-friction argument); libafl/honggfuzz/OSS-Fuzz
|
||||
not adopted. Sanitizer: `--sanitizer=address` with debug assertions
|
||||
(cargo-fuzz defaults) — no MSAN (no `unsafe` in this crate).
|
||||
|
||||
**Layout (the alkcall pattern, load-bearing):**
|
||||
|
||||
```
|
||||
fuzz/
|
||||
├── Cargo.toml alktunnels-fuzz (nightly-only bins; own [workspace])
|
||||
├── rust-toolchain.toml pins nightly for this subtree only
|
||||
├── fuzz_targets/ thin fuzz_target! wrappers (3-line each)
|
||||
│ ├── datagram_codec.rs
|
||||
│ └── params_parse.rs
|
||||
├── shared/ alktunnels-fuzz-shared — STABLE-toolchain library
|
||||
│ └── src/… invariant logic + corpus replay (§3)
|
||||
├── corpus/<target>/ committed hand-made seeds (§3)
|
||||
├── gen_fuzz_seeds.py deterministic seed generator (quiche pattern)
|
||||
├── run-detached.sh §6 detached runner (CWD-independent)
|
||||
└── README.md
|
||||
```
|
||||
|
||||
- **Invariant logic lives in `fuzz/shared/`**, not inline in the target
|
||||
binaries — the stable-toolchain corpus replay
|
||||
(`cargo test --manifest-path fuzz/shared/Cargo.toml`) runs the SAME
|
||||
invariant functions the fuzzer runs, on stable, in the release
|
||||
verification checklist. This is CI tier-3's deliverable (alkcall
|
||||
§7.2) minus automation; per alkcall §7.9 this repo has no hosted CI
|
||||
and will not get one (same gitea posture) — corpus replay as plain
|
||||
`cargo test` is the fuzz gate.
|
||||
- **Root `Cargo.toml` needs the explicit `[workspace]` table**
|
||||
(`members = ["."]`, `exclude = ["fuzz"]`) and `"fuzz/"` on the
|
||||
publish exclude list — without it cargo auto-discovers `fuzz/shared/`
|
||||
into the main workspace and the MSRV toolchain tries to build the
|
||||
nightly-consumed dev-deps (the exact failure alkcall hit).
|
||||
- **Corpus policy:** commit hand-made seeds, gitignore grown corpora
|
||||
(quinn/h2 model). Seeds per target: valid frames, truncation at every
|
||||
short prefix length, `len = 0` / `len = MAX` / `len = MAX+1`, empty
|
||||
datagrams, batching (two frames per chunk), splitting (one frame per
|
||||
many chunks), and for params: every substrate value, unknown
|
||||
substrate, unknown/missing fields, `listen: 0`, malformed reply
|
||||
shapes, untagged cross-shape targets, deep/invalid JSON.
|
||||
|
||||
## 3. Invariants by target
|
||||
|
||||
### 3.1 `datagram_codec` (wave 1)
|
||||
|
||||
Input: raw `&[u8]` (and in the shared logic, chunk-slice parameter
|
||||
arbitrary). Drives `DatagramReader::feed` + `frame_datagram`
|
||||
(`src/wire.rs`). Invariants:
|
||||
|
||||
- **no-panic on any byte sequence** (the baseline; the one
|
||||
`unreachable!` in `feed` is a structural invariant of the state
|
||||
machine — the target is how it stays true).
|
||||
- **infallibility**: `feed` never errors (contract — oversize is
|
||||
rejected at frame time; the decode direction is infallible by
|
||||
design, `src/wire.rs` docs).
|
||||
- **datagram-size bound**: every yielded datagram is
|
||||
`<= MAX_DATAGRAM_LEN` (u16 frame field makes this structural — the
|
||||
target pins it against future refactors).
|
||||
- **no partial yields**: a datagram completes only when exactly
|
||||
`declared` payload bytes are buffered (`is_mid_datagram` observable
|
||||
consistency); `feed(&[])` never yields anything and never clears
|
||||
mid-datagram state.
|
||||
- **round-trip**: `feed(frame_datagram(x)) == [x]` for any x; the
|
||||
reverse direction `write(feed-parse(x))` re-frames to the same
|
||||
frame for any well-framed input.
|
||||
- **F-2 sentinel layering**: `len == 0` is a legal empty datagram,
|
||||
never EOF; the codec never emits zero-length datagrams for non-empty
|
||||
frames and never treats an empty datagram as stream end.
|
||||
- **consumption accounting**: re-framing all consumed bytes and
|
||||
feeding the byte-level remainder yields the same datagram stream
|
||||
(splitting a feed at any boundary is transparent).
|
||||
- **oversize frame rejection**: `frame_datagram` errors iff payload >
|
||||
`MAX_DATAGRAM_LEN`, echoing the sizes.
|
||||
- **pending-queue bound (the §1.3 finding-class assertion)**: total
|
||||
bytes retained across `buf` + `current` + `pending` after a feed is
|
||||
bounded by the fed chunk size plus the one in-flight frame —
|
||||
an adversarial peer chunk cannot force unbounded queue growth in
|
||||
the decoder state. (NOTE: this is the *decoder-state* bound; the
|
||||
consumer-side `DatagramHalves.pending` backlog between chunk-read
|
||||
and `recv_datagram` pulls is a session-shape question tracked in
|
||||
§4/§8 — the wave-2 stateful target, or a code fix if the bound is
|
||||
judged unacceptable. The fuzzer documents the amplification factor;
|
||||
the remediation decision is ours.)
|
||||
|
||||
### 3.2 `params_parse` (wave 1)
|
||||
|
||||
Input: raw bytes → `serde_json` (with alkcall's bounded
|
||||
`arbitrary_value` approach — depth/width-capped `Value` generation) →
|
||||
`TunnelParams` / `TunnelDirectParams` / `TunnelForwardedParams` /
|
||||
`SubstrateAddr` deserialization + `parse_listen_reply` /
|
||||
`listen_reply_fields` (`src/params.rs`). Invariants:
|
||||
|
||||
- **no-panic on any JSON-shaped input** (untagged-enum serde dispatch,
|
||||
`deny_unknown_fields`, the `positive_u32` pin).
|
||||
- **clean failure only**: parse failures are `Err`, never panics;
|
||||
`parse_listen_reply` returns `TunnelError::MalformedReply` on
|
||||
malformed shapes.
|
||||
- **round-trip for valid params**: `from_json(to_json(p)) == p` for
|
||||
constructed params of every substrate.
|
||||
- **deny-unknown posture**: unknown top-level fields reject;
|
||||
untagged-variant leniency (extra fields inside a `SubstrateAddr`
|
||||
variant) is the documented asymmetry — asserted, not "fixed".
|
||||
- **the `listen: 0` pin**: zero rejects at serde level.
|
||||
- **projection agreement**: `listen_reply_fields` yields both-`Some`
|
||||
iff `parse_listen_reply` is `Ok`; it never panics and never refuses
|
||||
construction (the lenient view projects malformed to both-`None`).
|
||||
- **establishment-reason surface**: `establishment_reason` never
|
||||
panics on arbitrary `ChannelOpenError` shapes.
|
||||
|
||||
## 4. Scope: two waves
|
||||
|
||||
**Wave 1 (this session):** the two targets above. Both drive already-
|
||||
`pub` APIs — no `#[cfg(fuzzing)]` exposure needed (matching alkcall's
|
||||
experience where none of five targets needed it).
|
||||
|
||||
**Wave 2 (deferred):** a stateful op-sequence target over the two-pump
|
||||
tunnel shape in the alkcall `manager_routing` style (`#[derive(Arbitrary)]`
|
||||
op enum; live mux runner; the alkcall harness lessons apply: per-
|
||||
receiver EOF-sentinel latching, odd/even id ranges on adopt/open).
|
||||
Drives: `TunnelSession` pump lifecycle + the producer open handlers —
|
||||
the two-pump shutdown-on-completion contract (AGENTS.md convention 8)
|
||||
and the EOF-sentinel teardown semantics, with byte-accounting
|
||||
invariants across `pump_bidi`. Also: a `forwarded_routing` correlation
|
||||
target if the assembly-side correlation registry (ADR-008 §3, assembly
|
||||
bookkeeping) grows into this crate. Highest harness cost of anything
|
||||
here — the wave-1 targets will be saturated long before this one pays
|
||||
its setup cost, which is exactly why it is deferred, not dropped.
|
||||
|
||||
Sequencing mirrors alkcall §7.4: init + wave-1 targets → 10–30 min
|
||||
campaigns per target via the detached runner → fix anything found →
|
||||
wave 2 when justified.
|
||||
|
||||
## 5. Operational isolation: campaigns never share fate with the agent session
|
||||
|
||||
**This is an environment constraint, not a nice-to-have** (upstream
|
||||
doc §7.6, adopted verbatim as policy here). Agent sessions (opencode)
|
||||
run fuzzer builds/campaigns through a bash tool that spawns the fuzzer
|
||||
as a **child of the session's own process tree and cgroup**. A fuzz
|
||||
run is precisely the workload shape that kills its own host:
|
||||
|
||||
- **OOM-killer shared fate**: the target's worst case IS unbounded
|
||||
allocation. If libFuzzer's soft RSS guard loses the race with the
|
||||
kernel, the OOM killer fires — and it picks the largest-RSS process
|
||||
in the cgroup, which can be the opencode server hosting the session.
|
||||
That is *recoverable* (sessions are recorded in a DB) but hugely
|
||||
derailing — the session's live environment access dies mid-task.
|
||||
An OOM in a fuzz target must cost the fuzzer, never the session.
|
||||
- **Fork bombs / CPU saturation**: `-fork=N` workers; a runaway
|
||||
campaign starves the session host.
|
||||
- **Wedged targets**: a deadlock in an async harness would hang a
|
||||
foreground bash call forever.
|
||||
|
||||
Three layers of defense, cheapest first — **all mandatory**:
|
||||
|
||||
1. **libFuzzer soft limits (always on)**: `-rss_limit_mb=2048`
|
||||
`-malloc_limit_mb=2048` make libFuzzer exit cleanly (artifact
|
||||
recorded) before the kernel gets involved. Note the RSS limit is
|
||||
*soft* (polls `/proc/self/statm`); a fast huge allocation can beat
|
||||
it — that is what layers 2–3 are for. Never `ulimit -v` with ASAN
|
||||
(it reserves terabytes of virtual address space); the ASAN-safe
|
||||
hard-limit recipe is `-fork=1`.
|
||||
2. **Fork mode as blast-radius containment (default)**: `-fork=1`
|
||||
(or a small number) runs each input in a short-lived child — a
|
||||
crash/timeout/OOM/leak kills only that child; the harness survives,
|
||||
records the artifact, keeps fuzzing. Also the deadlock answer: the
|
||||
per-input timeout kills the child, not the session's bash call.
|
||||
3. **Process detachment from the session tree (MANDATORY for agent-run
|
||||
campaigns)**: never run fuzzing as a foreground child of the
|
||||
session. The runner script wraps `cargo fuzz run` in `setsid` +
|
||||
`nohup` + full redirection to a log file: (a) removes the fuzzer
|
||||
from the session's controlling terminal and signal relation, (b)
|
||||
survives the session ending, (c) gives the agent a pollable log +
|
||||
artifact directory instead of a blocking call. Combined with fork
|
||||
mode, an OOM-class finding costs one child process.
|
||||
|
||||
**The runner** (`fuzz/run-detached.sh`, CWD-independent — resolves its
|
||||
own repo root):
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# Detached fuzzing runner for agent sessions: the campaign never runs
|
||||
# as a foreground child of the session (an OOM in a target must cost
|
||||
# the fuzzer, never the agent host), and survives the session ending.
|
||||
set -euo pipefail
|
||||
target="${1:?usage: run-detached.sh <target> [extra libfuzzer args...]}"
|
||||
shift
|
||||
runtime="${FUZZ_RUNTIME_SECS:-600}"
|
||||
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
log_dir="$root/fuzz/artifacts"
|
||||
mkdir -p "$log_dir"
|
||||
log="$log_dir/${target}-$(date -u +%Y%m%d-%H%M%S).log"
|
||||
cd "$root"
|
||||
setsid nohup cargo fuzz run "$target" -- \
|
||||
-fork=1 -rss_limit_mb=2048 -malloc_limit_mb=2048 -timeout=25 \
|
||||
-max_total_time="$runtime" "$@" \
|
||||
>"$log" 2>&1 < /dev/null &
|
||||
echo "pid=$! log=$log"
|
||||
```
|
||||
|
||||
**Agent polling protocol** (never `wait` on the detached process from a
|
||||
tool call — poll instead):
|
||||
|
||||
- `tail -n 50 fuzz/artifacts/<target>-*.log` — campaign progress.
|
||||
- `ls fuzz/artifacts/` — `crash-*` / `oom-*` / `timeout-*` / `leak-*`
|
||||
artifacts are the findings.
|
||||
- `pgrep -f "cargo fuzz run <target>"` — still running?
|
||||
- One detached campaign per target at a time; log filenames carry the
|
||||
UTC timestamp.
|
||||
|
||||
**Flags worth pinning beyond the runner defaults**: `-max_len=65536`
|
||||
on the codec target; `-use_value_profile=1`; a JSON token `-dict` for
|
||||
the params target (alkcall's `json.dict` transfers as-is).
|
||||
|
||||
## 6. No hosted CI
|
||||
|
||||
Per alkcall §7.9 — the standing policy applies to this repo identically:
|
||||
no hosted CI will exist; do not add Actions/Gitea-Actions workflow
|
||||
files. **Corpus replay is the fuzz gate as plain `cargo test`**:
|
||||
`cargo test --manifest-path fuzz/shared/Cargo.toml` replays every
|
||||
committed seed through the invariant functions — add it to the release
|
||||
verification checklist (AGENTS.md). Campaigns run manually via the
|
||||
detached runner (§6) — e.g. before a release, or after touching
|
||||
`src/wire.rs`, the consumer data planes, or `src/params.rs`.
|
||||
|
||||
## 7. Implementation log
|
||||
|
||||
- **2026-09-28 — proposal adopted** (this doc). Wave-1 targets
|
||||
`datagram_codec` + `params_parse`; wave-2 deferred (§4).
|
||||
- **2026-09-28 — `alkcall` bumped 0.8.0 → 0.8.1.** Bug-fix release, no
|
||||
API/wire change; the fix (duplicate adopt/open no longer destroying
|
||||
the live channel) is directly relevant to this crate's
|
||||
`TunnelSession::adopt` path — the changelog's "open-op response
|
||||
replayed / id re-announced" scenario is our reverse path. Verification:
|
||||
full suite (135 passed), clippy, fmt, wasm check (§8 commands).
|
||||
- **2026-09-28 — wave-1 implemented.** `fuzz/` workspace laid out per
|
||||
§2 (nightly-pinned subtree, stable `fuzz/shared` library, runner,
|
||||
dict, generator); `datagram_codec` + `params_parse` targets over
|
||||
already-`pub` APIs — no `#[cfg(fuzzing)]` exposure needed. One new
|
||||
public diagnostic: `DatagramReader::retained_bytes()` (the
|
||||
decoder-state byte count the §3.1 bound asserts against, in the
|
||||
`is_mid_datagram` diagnostic style). Seeds committed: 27 +
|
||||
69 generated (fuzz/gen_fuzz_seeds.py) + 1 campaign-found crash
|
||||
input promoted to `datagram_codec/seed-900` (see the finding below).
|
||||
Stable side: corpus replay green, shared crate clippy/fmt clean;
|
||||
main suite untouched and green; `cargo fuzz build` clean.
|
||||
- **2026-09-28 — first campaign finding: a HARNESS-model bug, not a
|
||||
crate bug.** The `datagram_codec` campaign crashed in its first
|
||||
minute on input `00 2b 01 00 00 05` (`fuzz/artifacts/datagram_codec/
|
||||
crash-e9ba284e…`, exit 77, fork-mode containment worked as
|
||||
designed — the harness parent survived and persisted the artifact).
|
||||
Analysis: the codec is CORRECT — `00 2b` declares a 43-byte
|
||||
datagram; `01 00 00 05` is its in-flight payload; nothing is
|
||||
yielded. The invariant that tripped ("an empty datagram must come
|
||||
only from a [00 00] length header") was mis-modeled: it counted
|
||||
`00 00` byte pairs anywhere in the RAW stream, but a `00 00` pair
|
||||
sitting INSIDE a frame's payload region is payload, not a length
|
||||
header — exactly the same class as alkcall §7.7's probe (the
|
||||
harness claimed `4 + len` when the prefix counts only the body).
|
||||
Fix: the count now walks the framing as the decoder does (complete
|
||||
frames from the start; the walk stops where the decoder would be
|
||||
stuck mid-frame). The crash input is committed as seed-900 and
|
||||
replays clean; the campaign relaunched clean.
|
||||
- **2026-09-28 — second harness finding (caught by corpus replay,
|
||||
pre-campaign): `establishment_reason` is a pass-through extractor,
|
||||
not a validated table.** The params.rs doc names the pinned reason
|
||||
strings, but the upstream implementation (alkcall
|
||||
`channels/client.rs` `establishment_reason`) extracts
|
||||
`details.reason` AS-IS whenever the code is `channel:open_failed` —
|
||||
a made-up reason is surfaced as-is by design, and validation is the
|
||||
consumer's job. The harness first asserted a closed set of reason
|
||||
strings and corpus replay tripped it on `made_up_reason` before any
|
||||
campaign ran. Invariant corrected to assert the extraction shape
|
||||
(Some iff code == `channel:open_failed` and reason is a string).
|
||||
- **2026-09-28 — second harness finding (same replay pass):
|
||||
`is_mid_datagram` means a partial DATAGRAM, not buffered header
|
||||
bytes.** A dangling 1-byte length prefix at input end is buffered
|
||||
header state (no frame in flight, `is_mid_datagram == false`);
|
||||
the harness first asserted `true` for that case. Corrected:
|
||||
mid-datagram iff the framing walk leaves a remainder ≥ 2 bytes
|
||||
(a parsed-but-unfinished payload), not `!= 0`.
|
||||
- **2026-09-28 — wave-1 campaigns run (10-min detached runs, §6 runner;
|
||||
`-fork=1 -rss_limit_mb=2048 -malloc_limit_mb=2048 -timeout=25`;
|
||||
codec with `-max_len=65536`, params with `-dict=json.dict
|
||||
-use_value_profile=1`). Both exited 0.**
|
||||
- `params_parse` — 3.14M execs (~5.3k exec/s), 33 fork jobs,
|
||||
`oom/timeout/crash: 0/0/0` throughout. Coverage 2049 edges /
|
||||
15.6k features; in-memory corpus 69 committed seeds → 3018
|
||||
entries — the serde/untagged-enum shape space was still expanding
|
||||
at budget end, so longer campaigns keep paying here.
|
||||
- `datagram_codec` (post-harness-fix) — 827k execs, 33 fork jobs,
|
||||
`oom/timeout/crash: 0/0/0` throughout. Coverage saturated at 221
|
||||
edges (ft 1198) — the 2-byte-header state machine is fully
|
||||
enumerated, matching alkcall §7.7's `chunk_header` saturation
|
||||
profile. Exec/s reads low (~400) because each exec replays the
|
||||
input through a ~35-feed 3-byte-sliced sequence alongside the
|
||||
whole-input feed; the state space is small and exhausted early.
|
||||
- The pre-fix `datagram_codec` run (the §7 finding above) crashed at
|
||||
job 4 and exited 77; fork-mode containment behaved as designed —
|
||||
the harness survived, persisted the artifact, and the run wrapped
|
||||
up. That artifact is the promoted seed-900.
|
||||
- Grown corpora (3018 params entries) were **not** merged into the
|
||||
committed seeds — per the §2 policy, grown corpora stay
|
||||
gitignored.
|
||||
- Operational note for future sessions: `cargo fuzz run` returns
|
||||
before its last fork-mode children fully exit; a `pkill -f
|
||||
"cargo fuzz run <target>"` followed immediately by another
|
||||
`pgrep` of the same pattern can wedge a bash tool call on its own
|
||||
process match — prefer `pgrep -af` to LIST, kill by explicit pid
|
||||
from the runner's echoed `pid=`, and never pattern-kill-and-recheck
|
||||
in one call.
|
||||
- **NO crate bugs found by wave 1.** The two findings this session
|
||||
were both harness-model defects (§7 above), each invisible to
|
||||
example-based review and caught by fuzzing/replay — the alkcall §7.7
|
||||
"fuzzer as a harness-checker" pattern, confirmed. The §1.3
|
||||
decoder-state bound held everywhere: `retained_bytes()` never
|
||||
exceeded fed + one frame on any adversarial input. The session-shape
|
||||
`DatagramHalves.pending` amplification remains a documented
|
||||
§1.3/§4 note (wave-2's motivation), not a campaign finding — the
|
||||
wave-1 targets assert the decoder, not the session pump.
|
||||
- (progress appended as implementation proceeds — see git log)
|
||||
|
||||
## 8. Verification commands
|
||||
|
||||
```bash
|
||||
cargo test # main suite (stable)
|
||||
cargo test --manifest-path fuzz/shared/Cargo.toml # corpus replay (fuzz gate)
|
||||
cargo fuzz build # in fuzz/ (nightly, ASAN)
|
||||
fuzz/run-detached.sh <target> # campaigns (never foreground)
|
||||
cargo clippy --all-targets -- -D warnings
|
||||
cargo fmt --check
|
||||
cargo clippy --manifest-path fuzz/shared/Cargo.toml --all-targets -- -D warnings
|
||||
cargo fmt --manifest-path fuzz/shared/Cargo.toml --check
|
||||
cargo check --target wasm32-unknown-unknown # default crate stays wasm-clean
|
||||
```
|
||||
|
||||
## 9. References
|
||||
|
||||
- Upstream campaign + operational model (authoritative for tooling,
|
||||
runner, corpus policy, no-CI posture):
|
||||
`/workspace/@alkdev/alkcall/docs/research/fuzzing.md`
|
||||
- alkcall 0.8.1 changelog — the finding our adopt path is exposed to
|
||||
- This crate: ADR-003 (codec framing), ADR-002 (ALPN), ADR-007/008
|
||||
(direct/forwarded ops), `docs/architecture/wire.md`
|
||||
- External: RUSTSEC-2026-0037 (quinn-proto — the maintainers'
|
||||
fuzzing-coverage statement), rust-fuzz trophy case, cargo-fuzz Rust
|
||||
Fuzz Book (all linked from the upstream doc's §9)
|
||||
@@ -0,0 +1,9 @@
|
||||
target
|
||||
corpus/*
|
||||
!corpus/datagram_codec
|
||||
!corpus/params_parse
|
||||
# Grown corpus entries (libFuzzer hash-named) are gitignored; only the
|
||||
# hand-made seed-* files are committed (the quinn/h2 policy).
|
||||
corpus/*/[0-9a-f]*
|
||||
artifacts
|
||||
coverage
|
||||
Generated
+1296
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,31 @@
|
||||
[package]
|
||||
name = "alktunnels-fuzz"
|
||||
version = "0.0.0"
|
||||
publish = false
|
||||
edition = "2021"
|
||||
|
||||
[package.metadata]
|
||||
cargo-fuzz = true
|
||||
|
||||
[dependencies]
|
||||
libfuzzer-sys = "0.4"
|
||||
alktunnels-fuzz-shared = { path = "shared" }
|
||||
|
||||
[dependencies.alktunnels]
|
||||
path = ".."
|
||||
|
||||
[[bin]]
|
||||
name = "datagram_codec"
|
||||
path = "fuzz_targets/datagram_codec.rs"
|
||||
test = false
|
||||
doc = false
|
||||
bench = false
|
||||
|
||||
[[bin]]
|
||||
name = "params_parse"
|
||||
path = "fuzz_targets/params_parse.rs"
|
||||
test = false
|
||||
doc = false
|
||||
bench = false
|
||||
|
||||
[workspace]
|
||||
@@ -0,0 +1,56 @@
|
||||
# alktunnels fuzzing
|
||||
|
||||
libFuzzer targets for alktunnels' untrusted-input surfaces (see
|
||||
`docs/research/fuzzing.md` for the full rationale, scope decision, and
|
||||
campaign plan; the tooling/corpus/runner/no-CI posture is inherited
|
||||
from alkcall's `docs/research/fuzzing.md`).
|
||||
|
||||
## Layout
|
||||
|
||||
- `fuzz_targets/` — one binary per target; thin `fuzz_target!` wrappers.
|
||||
- `shared/` — the invariant logic, as a plain library so normal
|
||||
`cargo test` (stable toolchain) can replay the committed corpora
|
||||
through the same invariants (`fuzz/shared/src/*.rs` `#[cfg(test)]`
|
||||
modules; quinn's CI pattern). The fuzz binaries are nightly-only;
|
||||
the shared crate is stable-clean.
|
||||
- `corpus/<target>/` — committed hand-made seeds (regenerate with
|
||||
`python3 fuzz/gen_fuzz_seeds.py` from the repo root). Grown corpora
|
||||
and artifacts are gitignored.
|
||||
- `run-detached.sh` — mandatory runner for agent sessions: wraps
|
||||
`cargo fuzz run` in `setsid` + `nohup` + log redirection so an OOM
|
||||
in a target can never take down the agent host (fuzzing.md §5).
|
||||
- `json.dict` — JSON token dictionary for the params target
|
||||
(transferred from alkcall).
|
||||
|
||||
## Targets
|
||||
|
||||
| Target | Drives | Invariants |
|
||||
|---|---|---|
|
||||
| `datagram_codec` | `DatagramReader::feed` / `frame_datagram` (`src/wire.rs`) | no-panic; infallible decode; yielded datagrams ≤ `MAX_DATAGRAM_LEN`; F-2 sentinel layering (empty datagram ≠ EOF, only from `[00 00]` headers); splitting transparency (3-byte slices == whole-input feed); re-frame round-trip; oversize rejection exactly at the bound; `is_mid_datagram` tracks framing; decoder-state retained-bytes bound |
|
||||
| `params_parse` | `TunnelParams` / `TunnelDirectParams` / `TunnelForwardedParams` / `SubstrateAddr` serde parses + `parse_listen_reply` / `listen_reply_fields` / `establishment_reason` (`src/params.rs`) | no-panic on raw bytes and structured Values; clean typed failure only; round-trip for valid params; `listen: 0` pin; loud/lenient projection-pair agreement; pinned establishment-reason table |
|
||||
|
||||
## Commands
|
||||
|
||||
`cargo fuzz build` and `cargo fuzz run` must be executed with `fuzz/`
|
||||
(or deeper) as the working directory so rustup selects the pinned
|
||||
nightly toolchain — the detached runner handles that itself.
|
||||
|
||||
```sh
|
||||
# build (nightly, pinned by rust-toolchain.toml inside fuzz/; run from fuzz/)
|
||||
cargo fuzz build
|
||||
|
||||
# agent sessions: detached campaign (never foreground; CWD-independent)
|
||||
FUZZ_RUNTIME_SECS=600 fuzz/run-detached.sh datagram_codec -max_len=65536
|
||||
FUZZ_RUNTIME_SECS=600 fuzz/run-detached.sh params_parse -dict=json.dict -use_value_profile=1
|
||||
|
||||
# corpus replay through the invariants (stable toolchain, no nightly)
|
||||
cargo test --manifest-path fuzz/shared/Cargo.toml
|
||||
|
||||
# coverage
|
||||
cargo fuzz coverage <target>
|
||||
```
|
||||
|
||||
The fuzz workspace is excluded from the main workspace and from the
|
||||
published package (`exclude` in the root `Cargo.toml`); it pins its own
|
||||
nightly toolchain via `rust-toolchain.toml` and does not affect the
|
||||
crate's stable MSRV.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
��bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbLine truncated
|
||||
Whitespace-only changes.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
��
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
��
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
4
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1 @@
|
||||
{"resource": "postgres-primary", "substrate": "tcp"}
|
||||
@@ -0,0 +1 @@
|
||||
{"resource": "postgres-primary", "substrate": "udp"}
|
||||
@@ -0,0 +1 @@
|
||||
{"resource": "sock", "substrate": "unix"}
|
||||
@@ -0,0 +1 @@
|
||||
{"resource": "r", "substrate": "tcp", "extra": true}
|
||||
@@ -0,0 +1 @@
|
||||
{"substrate": "tcp"}
|
||||
@@ -0,0 +1 @@
|
||||
{"resource": "r"}
|
||||
@@ -0,0 +1 @@
|
||||
{"resource": "", "substrate": ""}
|
||||
@@ -0,0 +1 @@
|
||||
{"resource": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "substrate": "tcp"}
|
||||
@@ -0,0 +1 @@
|
||||
{"resource": null, "substrate": "tcp"}
|
||||
@@ -0,0 +1 @@
|
||||
{"resource": 1, "substrate": 2}
|
||||
@@ -0,0 +1 @@
|
||||
{"substrate": "tcp", "target": {"host": "db.internal", "port": 5432}}
|
||||
@@ -0,0 +1 @@
|
||||
{"substrate": "udp", "target": {"host": "10.0.0.7", "port": 53}}
|
||||
@@ -0,0 +1 @@
|
||||
{"substrate": "unix", "target": {"path": "/run/x.sock"}}
|
||||
@@ -0,0 +1 @@
|
||||
{"substrate": "tcp", "target": {"port": 1}}
|
||||
@@ -0,0 +1 @@
|
||||
{"substrate": "tcp", "target": {"host": "h"}}
|
||||
@@ -0,0 +1 @@
|
||||
{"substrate": "unix", "target": {"path": "/p", "host": "h"}}
|
||||
@@ -0,0 +1 @@
|
||||
{"substrate": "tcp", "target": {"host": "h", "port": 65536}}
|
||||
@@ -0,0 +1 @@
|
||||
{"substrate": "tcp", "target": {"host": "h", "port": -1}}
|
||||
@@ -0,0 +1 @@
|
||||
{"substrate": "tcp", "target": [1, 2]}
|
||||
@@ -0,0 +1 @@
|
||||
{"substrate": "unix", "target": {"host": "h", "port": 1}}
|
||||
@@ -0,0 +1 @@
|
||||
{"substrate": "tcp", "target": {}}
|
||||
@@ -0,0 +1 @@
|
||||
{"substrate": "tcp"}
|
||||
@@ -0,0 +1 @@
|
||||
{"target": {"host": "h", "port": 1}}
|
||||
@@ -0,0 +1 @@
|
||||
{"listen": 918273, "substrate": "tcp", "peer": {"host": "198.51.100.4", "port": 55231}}
|
||||
@@ -0,0 +1 @@
|
||||
{"listen": 918273, "substrate": "unix", "peer": {"path": "/run/x.sock"}}
|
||||
@@ -0,0 +1 @@
|
||||
{"listen": 0, "substrate": "tcp", "peer": {"host": "h", "port": 1}}
|
||||
@@ -0,0 +1 @@
|
||||
{"listen": -1, "substrate": "tcp", "peer": {"host": "h", "port": 1}}
|
||||
@@ -0,0 +1 @@
|
||||
{"listen": 1, "substrate": "tcp", "peer": {"host": "h", "port": 1}, "channel": 7}
|
||||
@@ -0,0 +1 @@
|
||||
{"listen": 4294967296, "substrate": "tcp", "peer": {"host": "h", "port": 1}}
|
||||
@@ -0,0 +1 @@
|
||||
{"listen": "token", "substrate": "tcp", "peer": {"host": "h", "port": 1}}
|
||||
@@ -0,0 +1 @@
|
||||
{"substrate": "tcp", "peer": {"host": "h", "port": 1}}
|
||||
@@ -0,0 +1 @@
|
||||
{"listen": 1, "substrate": "tcp"}
|
||||
@@ -0,0 +1 @@
|
||||
{"listen": 1, "substrate": "unix", "peer": {"path": "/p", "host": "h"}}
|
||||
@@ -0,0 +1 @@
|
||||
{"channel_id": 7, "bound": {"host": "203.0.113.9", "port": 42113}, "listen": 918273}
|
||||
@@ -0,0 +1 @@
|
||||
{"channel_id": 7}
|
||||
@@ -0,0 +1 @@
|
||||
{"channel_id": 0}
|
||||
@@ -0,0 +1 @@
|
||||
{"channel_id": 7, "bound": {"path": "/run/x.sock"}, "listen": 5, "future_field": {"n": true}}
|
||||
@@ -0,0 +1 @@
|
||||
{"channel_id": 7, "bound": {"port": 1}}
|
||||
@@ -0,0 +1 @@
|
||||
{"channel_id": 7, "listen": 0}
|
||||
@@ -0,0 +1 @@
|
||||
{"channel_id": 7, "listen": "token"}
|
||||
@@ -0,0 +1 @@
|
||||
{"bound": {"path": "/p"}}
|
||||
@@ -0,0 +1 @@
|
||||
{"channel_id": -7}
|
||||
@@ -0,0 +1 @@
|
||||
{"channel_id": 7.5}
|
||||
@@ -0,0 +1 @@
|
||||
{"channel_id": 7, "bound": 5}
|
||||
@@ -0,0 +1 @@
|
||||
{"channel_id": 7, "listen": 4294967296}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1 @@
|
||||
{"code": "channel:open_failed", "message": "establishment failed", "details": {"reason": "dial_failed"}}
|
||||
@@ -0,0 +1 @@
|
||||
{"code": "channel:open_failed", "details": {"reason": "unknown_resource"}}
|
||||
@@ -0,0 +1 @@
|
||||
{"code": "channel:open_failed", "details": {"reason": "resource_shortage"}}
|
||||
@@ -0,0 +1 @@
|
||||
{"code": "channel:open_failed", "details": {"reason": "handler_error"}}
|
||||
@@ -0,0 +1 @@
|
||||
{"code": "channel:open_failed", "details": {"reason": "timeout"}}
|
||||
@@ -0,0 +1 @@
|
||||
{"code": "channel:open_failed", "details": {"reason": "made_up_reason"}}
|
||||
@@ -0,0 +1 @@
|
||||
{"code": "forbidden"}
|
||||
@@ -0,0 +1 @@
|
||||
{"code": "channel:too_many_channels", "details": {"reason": "dial_failed"}}
|
||||
@@ -0,0 +1 @@
|
||||
{"details": null}
|
||||
@@ -0,0 +1 @@
|
||||
{"resource": ["a" * 1], "substrate": "tcp"}
|
||||
@@ -0,0 +1 @@
|
||||
{"resource": {"nested": {"deep": [1, 2, {"x": [1, [2, [3]]]}]}}, "substrate": "tcp"}
|
||||
@@ -0,0 +1 @@
|
||||
{"resource": "ÿþ", "substrate": "tcp"}
|
||||
@@ -0,0 +1 @@
|
||||
{"resource": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxLine truncated
|
||||
@@ -0,0 +1 @@
|
||||
{"substrate": {"enum": "tcp"}}
|
||||
@@ -0,0 +1 @@
|
||||
[{"resource": "r", "substrate": "tcp"}]
|
||||
@@ -0,0 +1 @@
|
||||
"just a string"
|
||||
@@ -0,0 +1 @@
|
||||
12345
|
||||
@@ -0,0 +1 @@
|
||||
null
|
||||
Loaded 100 of 116 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user