Rak

Rak .github release_body.md

10.8 KB 199 lines Raw ↗ GitHub ↗

# Rak v8.0.0## What's new in 8.0.0### Security primitives- **`unsafe "reason" { ... }` blocks.** Anything touching raw memory, FFI, or a  wire format can be wrapped in a block carrying a written justification. The  reason is enforced by the parser, so an unjustified exemption is a parse  error rather than a warning, and `grep unsafe` returns every exemption with the  author's own words attached. `rakc lint --audit` prints the same list as a  review artifact, and the interpreter records which blocks were actually  entered during a run. This is a review boundary, not a permission: the block  executes exactly as written.- **`requires` / `ensures` contracts on `fn`.** Preconditions are checked with  the parameters bound and before a single statement of the body, so a violated  precondition blames the caller and a function that would corrupt state before  validating never gets the chance. Postconditions run after deferred cleanup,  with `result` and the parameters in scope. Contracts survive into `async fn`,  on both the sequential and the concurrent drive path.- **`rakc verify`.** Runs a script under finite step, loop-iteration and  recursion-depth budgets. It reports three outcomes and they are deliberately  distinct, because conflating them would be misleading: `PASS` (completed, all  contracts held), `FAIL` (a contract broke, an assert tripped, or a runtime  error), and `SKIP` (a budget was hit, so nothing was proved). Exit code 2 means  inconclusive, never "looks fine".- **Constant-time comparison.** `ct_eq`, `ct_eq_hex`, and `ct_select`. Rak's `==`  is a data-dependent branch that leaks the length of a shared prefix through its  exit timing, which is enough to recover a MAC or a session token one byte at a  time.- **Zeroization.** `zeroize(bytes)` overwrites a buffer through a volatile path  the optimizer cannot elide. `secret_delete` and the new `secret_delete_all`  wipe values from memory and overwrite the store file with zeroes before  rewriting it. The serialized buffer in the secrets store is wiped too, and  file permissions are now set *before* the data lands rather than after.### Crypto- **RSA** — `rsa_keypair`, `rsa_sign`, `rsa_verify`, `rsa_encrypt`, `rsa_decrypt`  (PKCS#1 v1.5 over SHA-256, OAEP with SHA-256). Keys are DER.- **ECDSA over NIST P-256** — `ecdsa_keypair`, `ecdsa_sign`, `ecdsa_verify`, with  64-byte `r||s` signatures. DER keys.The suite previously had only Ed25519 and X25519, both non-standard curves, sonothing interoperated with ordinary OpenSSL tooling. Everything remains pure Rustwith no OpenSSL linkage.### Static analysis- Six new security lint rules: `hardcoded-secret`, `plaintext-url`,  `weak-crypto`, `secret-compare`, `ffi-raw-pointer`, `insecure-transport`, plus  `unsafe-thin-reason`.- This required fixing a real bug: the linter had no `Expr::String` arm, so  string literals fell through to `_ => {}` and no rule could ever inspect a  byte of user text. A hardcoded `sk-live-...` was completely invisible. There is  a regression test for exactly that.- `rakc fmt` and `rakc lint` are now listed in `rakc --help`.### Packet crafting- **ICMP** — `net_raw_icmp`, `net_raw_icmp_ping`, `net_raw_icmp_echo_reply`, with  matching `id`/`seq` so a reply can be correlated to its request.- **ARP** — `net_raw_arp_request`, `net_raw_arp_reply`, and `net_raw_arp_parse`,  which accepts a frame with or without the Ethernet header and returns `nil` on  anything that is not ARP, so raw capture can be fed straight in.`caps.rs` previously gated a `net_raw_icmp` builtin that did not exist; the gatenow matches real builtins, and packet *builders* are documented as reachableinside a sandbox because they only construct a `bytes` value.### Fuzzing on the stable toolchain- **`rakc fuzz <target>`** — a deterministic mutation loop in the compiler  itself, covering the lexer, parser, interpreter and the stdlib parsers. 12  targets, reproducible via `--seed`, with a crashing input written to disk and  the seed printed for replay.- The 13 `cargo-fuzz` targets in `fuzz/` are still there for long  coverage-guided campaigns, but they need nightly and `-fsanitize=fuzzer`,  which `stable-x86_64-pc-windows-msvc` cannot provide. Nothing was running them  automatically before this.### Build hardening- Release profile gains `lto = "fat"`, `codegen-units = 1`, `panic = "abort"`  and `strip = "symbols"`. The one that matters most is `overflow-checks = true`:  Cargo's default in release is `false`, which silently wraps and turns a length  calculation into a heap overflow.- `.cargo/config.toml` adds `/guard:cf`, `/CETCOMPAT`, `/DYNAMICBASE`,  `/HIGHENTROPYVA`, `/NXCOMPAT` on MSVC, and full RELRO, a non-executable stack,  a stack canary and forced frame pointers on Linux.- **Stated precisely, because these are easy to oversell.** `/guard:cf` marks the  image CFG-compatible and guards the dispatch table, but rustc does not  instrument Rust's own indirect calls, so there is no `__guard_check_icall` in  the binary. This is not equivalent to Clang's `-fsanitize=cfi`. It closes a  real class of bugs; it does not close ROP or JOP.- `dist/verify_hardening.py` reads the produced binary back and asserts the bits  are really set, and both release jobs run it. It has a `--self-test` covering  both the PE and ELF parsers on synthetic headers, positive and negative. This  already caught a real mistake: an early flag set passed both `/NXCOMPAT` and  `/NXCOMPAT:NO`, silently disabling DEP.### Validating the hardening against real binariesBoth platforms were checked before tagging, by building the actual `rakc` andreading the result back rather than trusting the flag list.- **Linux**: `rakc` (7.8 MB) built in WSL with the repo's exact  `.cargo/config.toml`. PIE, full RELRO, non-executable stack and `BIND_NOW`  all land correctly. The **stack canary does not**, and cannot be made to:  rustc's `x86_64-unknown-linux-gnu` target does not enable `-fstack-protector`,  and `-C target-feature=+stack-protector` is rejected outright with "not a  recognized feature for this target". Getting a canary into Rust code needs  nightly `-Z stack-protector`, or a C object built with GCC's  `-fstack-protector` and linked in.- So the verifier reports the canary as an **advisory** finding rather than a  required one. A check the stable toolchain cannot satisfy is either a  permanently red build or something everyone learns to ignore, and neither is  useful. The four checks that are satisfiable remain hard failures.- The same exercise turned up that `rustflags` is silently ignored when placed in  `Cargo.toml` ("unused manifest key"). It only takes effect in  `.cargo/config.toml`, which is where it lives. A virtual manifest also rejects  a `[target]` section outright.### Deep recursion no longer kills the processThe tree walker burned several native frames per Rak call, and a Rak call costsseveral KB of native stack in a debug build. `fib(15)` needed roughly a megabyte,which is more than the default thread stack allows, so a moderately recursiveprogram died with a bare "has overflowed its stack" and no Rak-level line number.The interpreter now runs on a thread with an explicit 64 MB stack. `rakc verify`additionally bounds recursion depth, loop iterations and total steps, so runawayrecursion is a reportable outcome rather than a crash.### Tooling- The VS Code TextMate grammar's builtin list was a single 2,900-character line,  close to TextMate's practical limits and unmaintainable. It is now 17 grouped  per-family patterns, the longest 371 characters.- The builtin lists in the LSP, the IDE editor, and the grammar were all stale  and disagreed with each other. All three are updated, and the LSP list had been  missing the entire batteries, OSINT, iterator, FFI, mmap and `net_raw` families.- New `docs/content/safety.md`, covering what is enforced and — just as  importantly — what is not.### Correctness- `docs/content/vm.md` claimed binary pattern matching, method-call dispatch and  user enum patterns were unsupported on the VM. All three shipped; the table was  wrong.- `Pattern::Bind` does not exist: the `@` binding-pattern syntax the spec  advertised does not parse. Marked `[SPEC]` rather than `[SHIPPED]`, with the  implementation steps recorded. Spec markers in both directions were wrong and  are now corrected against the code.- `expr_str` fell back to the AST debug form for calls, indexing, field access  and ranges. Contract clauses and assertion failures are mostly calls, so the  most important diagnostics were the least readable. Now rendered as source.### Housekeeping- All version strings moved to 8.0.0, including the REPL banner (still said  v0.3.0) and `rakpkg` (still said 0.7.0).- `raklib/` was an empty untracked directory. Removed.- `adblocker/` added to `.gitignore`: it is a nested git repository kept  deliberately local, and without this `git add -A` fails outright.- `scripts/run-tests-safe.ps1` runs the test binary under a memory and time  watchdog. A stack overflow becomes a Windows Error Reporting event, and with  the system default of automatic memory dumps that writes a multi-gigabyte file.## Known limitationsStated plainly rather than discovered later.- **The GUI is incomplete and Windows-only.** `gui_update`, `gui_title` and  `gui_close` are declared but do nothing: `gui.rs` stores `HashMap<i64, ()>` and  discards the `Window` and `WebView` handles. JavaScript cannot call into Rak —  the IPC handler receives the message and drops it. Closing a window ends the  process, because tao's `run` calls `process::exit`. Linux does not work at all,  because `gui_open` builds the event loop off the main thread, which tao  rejects. The VM has no GUI natives, so `rakc vm` reports  `Undefined: gui_open`. The README and docs now say this instead of implying  otherwise.- **No ownership or borrowing.** There is no `&` reference type; `&` is  bitwise-and. Values are shared rather than moved and there is no lifetime  tracking. This is a language redesign, not a version bump.- **No instrumented control-flow integrity.** See the hardening section above for  exactly what is and is not provided.- **No inline assembly.** `extern "C"` FFI is the escape hatch, and it is  capability-gated and lint-flagged.- **No formal verification.** Contracts are checked at runtime; there is no  prover, no loop invariants, no pre/postconditions in the refinement-type sense.- **No enclaves.** The capability sandbox is name-based and in-process. It does  not confine the process from the kernel. For genuinely untrusted code, run the  script in a container or a VM.- **Sets are not implemented** (7A.11), and the backend parity items in  `docs/rak-features-spec.md` Part 7A.4–7A.6 (VM streams, VM `tunnel`/`udp_*`, VM  `import pkg.sub`) remain open.`docs/V8-ROADMAP.md` records the reasoning and the cost for each gap.