Commit graph

7 commits

Author SHA1 Message Date
93f11ecef0 docs: rewrite for users — drop internal infra context
README + supporting docs were written for ourselves (deployment paths,
internal product comparisons, internal task lists, build pipeline
artifacts) instead of for users of the software. This pass refocuses
them on what the software is, how to install, configure, and use it.

- README.md: full rewrite. New shape — What it does / Architecture /
  Build / Run / Configuration / MCP tools / Security model / Status /
  License / Dependencies. Drops the internal "why we built it"
  narrative, drops phase-status claims that drifted stale, drops
  internal deployment paths.
- ROADMAP.md: deleted. Was an internal task-list with [x]/[ ] items
  showing incremental private development. The README's Status
  section now communicates what's actually shipped.
- docs/architecture.md: scrub cross-project comparisons referencing
  unrelated internal Sulkta codebases.
- aiken-escrow/README.md: drop reference to a non-existent spec file;
  rewrite the Status checklist to reflect what's actually done
  rather than what was open at the time of writing.
- audits/2026-05-09-escrow-e2e.md: scrub internal image names +
  container paths; the audit findings (chain hashes, validator hash,
  what each tx proved) are the public-useful part and stay.
- audits/2026-05-09-escrow-internal-audit.md: drop references to
  feature-flag-gated branches that no longer exist.
- Dockerfile: drop the dead `escrow_wip surface` phrase from comments.
- Cargo.toml: drop the cross-project comparison comment that named
  an unrelated internal service.
- crates/aldabra-{core,dao}: scrub internal preprod-test naming from
  source comments — same technical content, generic phrasing.
2026-05-10 20:56:25 -07:00
bc538a71fb docs: scrub remaining internal repo + tooling references
- README.md: drop "first Sulkta Rust project — workout for crafting-
  table's Rust toolchain" paragraph + the `crafting-table build aldabra`
  recipe. Both reference non-public Sulkta-internal infrastructure.
- Dockerfile: drop "Built nightly on Lucy (see lucy-infra/scripts/
  nightly-builds.sh)" comment + the `lucy-registry:5000/aldabra/mcp`
  internal image-name advertisement.
- Cargo.toml: drop the comment block referencing the deleted
  `docs/internal-build-rewrites.md` + `crafting-table + Lucy + dev
  hosts` Sulkta-internal-builds note. The patch block stands on its
  own.
2026-05-10 20:51:21 -07:00
8831774fb6 chore(build): drop URL rewrite layer + remove internal-rewrites doc
GitHub is canonical for aldabra now (per 2026-05-10 architecture call —
Gitea is a pull-mirror cache, not a forge we publish to). Build process
fetches pallas direct from github.com, no rewrite needed.

- Dockerfile: drop the `--mount=type=secret` git_credentials dance + the
  url.insteadOf rewrite. cargo fetches pallas straight from
  github.com/Sulkta-Coop/pallas at the locked SHA. No secret needed.
- docs/internal-build-rewrites.md: removed. The rewrite was the entire
  reason for the doc, and the rewrite is gone.

Internal builds (Lucy / crafting-table / dev hosts) still hit
github.com for pallas, same as external builds. One extra WAN hop per
crate, but consistent everywhere and no environment-specific config.
2026-05-10 17:32:25 -07:00
bdbb7e0539 chore: replace LAN-IP refs with public mirror URLs
Cargo.toml + Cargo.lock now point at https://github.com/Sulkta-Coop/pallas
for the pallas-fork patch entries. External clones from either public
mirror (github.com/Sulkta-Coop or gitlab.com/sulkta) build out of the box
— no LAN access needed.

Sulkta-internal builds short-circuit to LAN gitea via a `git config
url.X.insteadOf` rewrite on each host. Symmetric: covers both github and
gitlab → gitea. Same locked SHA either way; routing is environment-level,
not source-of-truth. See docs/internal-build-rewrites.md.

Dockerfile build-time rewrite also flipped to take public-URL inputs;
uses `gitea.sulkta.lan` instead of the bare LAN IP.
2026-05-10 14:46:05 -07:00
eb192fa676 fix(escrow_wip): apply 2026-05-09 internal audit findings
Two HIGH validator-side bugs + several MED/LOW off-chain issues found
in the subagent-driven audit on this branch. New validator hash:
a8081acef26935d9b5f44b92052178e17301b6d6e6808c91c5b56f5d.

## HIGH-1: Deposit redeemer let depositors drain tokens

aiken-escrow/validators/escrow.ak Deposit branch now requires
`value_geq_value(new_value, in_value)` before computing net_added.
Previously net_added could carry negative quantities (when new_value
< in_value component-wise), letting a depositor write a matching
new_d.deposits with reduced values and pocket the difference as
wallet change. Latent under v1 ADA-only MCP usage but the validator
must hold against all callers.

## HIGH-2: Empty/partial deposits enabled funds drain via Veto/Refund

Veto and Refund branches now require
`value_eq(deposits_to_value(d.deposits), in_value)` — the tracked
deposits must account for the full locked value. Previously
`refund_outputs_satisfy(_, [])` was vacuously true on empty deposits,
so a driver could fire Veto/Refund on an escrow opened with
`initial_contributor=None` (deposits=[], in_value>0) and pocket the
input's lovelace as change.

Defense in depth: escrow_open builder now refuses
`initial_contributor=None`. New helper `deposits_to_value` folds
deposit FlatValues into a Value via `assets.add` for the equality
check.

## MED: off-chain fixes

- escrow_open min-utxo bumped 1M → 2M (Conway-era inline-datum
  + script-address outputs need ~1.4-1.7 ADA, NOT the 1 ADA default).
- escrow_settle_unsigned + escrow_refund_timeout_unsigned now derive
  `validity_lower_ms` via slot_to_posix_ms(network, slot) instead of
  Koios's `block_time*1000` — the chain reconstructs `lower` from the
  slot, so Koios's ~1s drift could pass off-chain preflight while the
  chain rejects at the strict-`>` boundary.
- escrow_open_unsigned MCP tool no longer accepts (and silently
  discards) `fee_lovelace` — the unsigned-tx builder auto-estimates.

## LOW: defensive depth

- escrow_veto + escrow_refund_timeout: `qty as u64` → `u64::try_from`
  so a corrupt or adversarial datum with negative i128 qty can't slip
  through with a wraparound.

## Tests

- 36 escrow builder tests pass (added rejects_no_initial_contributor)
- 132 dao tests pass under --features escrow_wip
- aldabra-mcp release build clean

## Infra

- Validator artifact files (plutus.json, validator.cbor.hex)
  regenerated. Dockerfile already wired to bake them at
  /etc/aldabra/escrow/ for MCP tools' validator_script_path arg.
- Internal audit findings written up at
  audits/2026-05-09-escrow-internal-audit.md including the v2-deferred
  items (multi-asset spend-input, lovelace-not-cross-checked, etc.)

Third-party audit still required before any mainnet deployment.
2026-05-09 14:06:17 -07:00
82e8273969 build(docker): mount git credentials as buildkit secret for pallas SSH→HTTP fetch
The pallas patch in [patch.crates-io] is now ssh://git@gitea after the
2026-05-06 token-scrub. Inside a docker build the rust container has no
SSH key and no known_hosts for gitea, so cargo's libgit2 / system-git
both reject the fetch.

Mount /root/.git-credentials as a BuildKit secret (mode=0400, required)
and set a build-time `url.HTTP.insteadOf SSH` rewrite. Cargo.toml and
Cargo.lock keep their SSH URLs — the rewrite is git-CLI-level so no
credential ever lands in the lock file or in any image layer.

Build invocation:
  docker build --secret id=git_credentials,src=<creds-file> ...

where <creds-file> is one line `http://USER:PAT@192.168.0.5:3001`.

This mirrors the pattern crafting-table already uses on its runner
(.git-credentials + url.insteadOf rewrite). nightly-builds.sh on Lucy
will need an analogous --secret arg before it can rebuild this branch.
2026-05-06 13:45:55 -07:00
bc39148b63 phase 1: full read path — bip39 + cip-3 + cip-1852 + koios + age-mnemonic + rmcp
end-to-end working wallet: paste 24-word mnemonic, age-encrypt at rest,
on unlock derive root + payment + stake keys, build cip-19 base address,
serve four tools over mcp stdio (wallet.address, wallet.network,
wallet.balance, wallet.utxos).

deps added: ed25519-bip32 0.4 (pallas only ships raw ed25519, not the
cardano variant of bip32 hd derivation), cryptoxide 0.4 for pbkdf2-hmac-sha512,
age 0.10 for at-rest mnemonic encryption, rpassword 7 for tty-only passphrase
prompts, toml 0.9 for config.toml.

new modules:
- crates/aldabra-core/src/derive.rs — payment + stake key derivation, hash
- crates/aldabra-chain/src/koios.rs — real reqwest impl, asset aggregation
- crates/aldabra-mcp/src/{bootstrap,config,tools}.rs

caught one bug pre-flight: get_balance was clobbering same-asset
quantities across utxos instead of summing. fixed + regression test.

headless support via ALDABRA_PASSPHRASE env (mcp clients own stdin so
the rpassword prompt path can't run). docker secret / systemd
EnvironmentFile sources it in production.

dockerfile: multi-stage rust:1.95-bookworm → debian:bookworm-slim, tini
as pid1, non-root aldabra user, /var/lib/aldabra owned 700.

29 unit tests + 1 ignored live-koios test. preprod smoke test exercised
initialize → tools/list → tools/call wallet.address end-to-end via
piped json-rpc; correct preprod address came back from canonical
abandon-art mnemonic.

phase 2 (send) is next.
2026-05-04 11:09:00 -07:00