Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
97 changes: 97 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions PRICING.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ code.
Schema, conductor, rule engine, signed governance log, bridges — all of it,
Apache-2.0/MIT (see `LICENSE`), no key required, no phone-home, no feature
gated behind payment for someone running their own copy on their own
machine. `primeswarm-pchi`'s `/governance/export` route supports an
optional `PCHI_GOVERNANCE_KEY` — that's a *security* control for anyone
exposing a conductor beyond localhost, not a paywall; it defaults open.
machine. `primeswarm-pchi` supports an optional `PCHI_DASHBOARD_PASSWORD`
gating its dashboard, `/ws` feed, and `/governance/export` — that's a
*security* control for anyone exposing a conductor beyond localhost, not
a paywall; it defaults open. Same for `--rules`/`PCHI_RULES_FILE`: a
venue's own rule thresholds, loaded from a plain text file, free to write
and change as often as you like.

What's paid is work someone has to actually do on your behalf, not
software we could give you for free and chose not to:
Expand Down
24 changes: 22 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ This repository contains all the core libraries, tools, and documentation needed

```bash
cargo build # workspace root — builds pchi-schema and primeswarm-pchi
cargo test # 25 tests: schema validation, the Only-Lang parser/evaluator,
cargo test # 40 tests: schema validation, the Only-Lang parser/evaluator,
# signed-receipt chaining and tamper detection, end-to-end
# rule denial through the conductor
# rule denial through the conductor, dashboard auth
```

## Governance — what's real
Expand All @@ -37,6 +37,26 @@ curl http://127.0.0.1:3000/governance/export > export.json
python3 scripts/verify_governance_chain.py export.json
```

A fresh checkout runs the bundled default rule set
(`pchi-schema/examples/kraken-tentacle.only-pchi`). Point it at a
different `.only-pchi` file for a real venue/show instead — no recompile
needed:

```bash
cargo run -p primeswarm-pchi -- --rules ./my-venue-rules.only-pchi
# or: PCHI_RULES_FILE=./my-venue-rules.only-pchi cargo run -p primeswarm-pchi
```

The dashboard, its `/ws` feed, and `/governance/export` are open by
default (self-hosted on a machine its operator already controls). Set
`PCHI_DASHBOARD_PASSWORD` to require HTTP Basic Auth (username
`operator`) before exposing a conductor beyond localhost:

```bash
PCHI_DASHBOARD_PASSWORD=change-me cargo run -p primeswarm-pchi
curl -u operator:change-me http://127.0.0.1:3000/governance/export
```

See `PRICING.md` for what's free (all of the above, unrestricted,
self-hosted) versus what's a real paid service, and `docs/LIMITATIONS.md`
for what this does and doesn't yet prove.
Expand Down
31 changes: 21 additions & 10 deletions docs/LIMITATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,27 @@ separately; there is no cross-conductor verification story yet.
**Not yet built:** the Cloud Conductor described in `PRICING.md` is the
natural place to add this.

## 4. `/governance/export` Access Control Is Opt-In, Not Default-Closed

`PCHI_GOVERNANCE_KEY` gates the export endpoint when set; it is **open by
default**, deliberately, because this conductor is meant to be
self-hosted on a machine its operator already controls — unlike DGV's
`/decisions/export`, which was found open on a genuinely multi-tenant,
publicly reachable deployment and is now closed by default (see DGV's
`LIMITATIONS.md` §4 for that finding). If you expose a PCHI conductor
beyond localhost, set the key yourself; the software will not do it for
you.
## 4. Dashboard Access Control Is Opt-In, Not Default-Closed

**[Improved]** `PCHI_DASHBOARD_PASSWORD`, when set, now gates all three
HTTP surfaces — the dashboard page (`/`), its `/ws` telemetry feed, and
`/governance/export` — behind HTTP Basic Auth (username `operator`),
not just the export endpoint on its own as the earlier
`PCHI_GOVERNANCE_KEY` did. It is still **open by default**, deliberately,
because this conductor is meant to be self-hosted on a machine its
operator already controls — unlike DGV's `/decisions/export`, which was
found open on a genuinely multi-tenant, publicly reachable deployment and
is now closed by default (see DGV's `LIMITATIONS.md` §4 for that
finding). If you expose a PCHI conductor beyond localhost, set the
password yourself; the software will not do it for you.

One real gap: a non-browser WebSocket client connecting to `/ws`
directly (not a page that already loaded `/` and cached credentials)
must send its own `Authorization: Basic ...` header on the handshake —
the plain browser `WebSocket` API has no way to attach one itself, so
this only works automatically for the dashboard's own JS, which inherits
credentials the browser cached from loading the authenticated page
first.

## 5. No Independent Security Review

Expand Down
2 changes: 2 additions & 0 deletions primeswarm-pchi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ futures-util = "0.3"
axum = { version = "0.7", features = ["ws"] }
tower = "0.5"
tower-http = { version = "0.5", features = ["fs", "cors"] }
clap = { version = "4", features = ["derive", "env"] }
base64 = "0.22"

[dev-dependencies]
tokio-test = "0.4"
58 changes: 58 additions & 0 deletions primeswarm-pchi/src/conductor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,4 +445,62 @@ mod tests {

let _ = std::fs::remove_dir_all(&dir);
}

#[tokio::test]
async fn with_rules_file_actually_uses_the_custom_rules_not_the_bundled_default() {
let dir = std::env::temp_dir().join(format!("pchi-rulesfile-test-{}", uuid::Uuid::new_v4()));
std::fs::create_dir_all(&dir).unwrap();

// A threshold (2.0) stricter than the bundled default's (4.0) —
// chosen so a value that the bundled rules would silently allow
// only denies if this file is genuinely the one in effect.
let rules_path = dir.join("strict.only-pchi");
std::fs::write(
&rules_path,
"harmony(1e-12)\n\nif tentacle_system.total_curl > 2.0 then\n deny(\"too strict for the bundled default to agree with\")\nend\n",
)
.unwrap();

let conductor = PCHIConductor::with_rules_file(
1e-12,
rules_path.to_str().unwrap(),
dir.join("key.hex").to_str().unwrap(),
dir.join("log.jsonl").to_str().unwrap(),
)
.unwrap();

let msg = PCHIMessage::new(
MessageType::ControlParameter,
"test".to_string(),
Payload::ControlParameter(ControlParameterData {
target_id: "tentacle_system".to_string(),
parameter: "total_curl".to_string(),
value: serde_json::json!(3.0),
}),
);
let result = conductor.process_message(msg).await;
assert!(
result.is_err(),
"3.0 is under the bundled default's 4.0 threshold but over this file's 2.0 — \
an error here proves the custom file is the one actually loaded"
);

let _ = std::fs::remove_dir_all(&dir);
}

#[tokio::test]
async fn with_rules_file_rejects_a_missing_path_instead_of_silently_falling_back() {
let dir = std::env::temp_dir().join(format!("pchi-rulesfile-missing-{}", uuid::Uuid::new_v4()));
std::fs::create_dir_all(&dir).unwrap();

let result = PCHIConductor::with_rules_file(
1e-12,
dir.join("does-not-exist.only-pchi").to_str().unwrap(),
dir.join("key.hex").to_str().unwrap(),
dir.join("log.jsonl").to_str().unwrap(),
);
assert!(result.is_err(), "a missing rules file must be a startup error, not a silent fallback");

let _ = std::fs::remove_dir_all(&dir);
}
}
Loading
Loading