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
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This document defines the interface and protocols for autonomous agents interact

## Autonomous Operating Rules
1. **Branch Isolation**: Never commit directly to `main`. Create feature branches (`feat/`, `fix/`, `perf/`), execute preflight checks, and open public Pull Requests immediately.
2. **Zero Disk Secrets**: Never write plaintext `.env` files. Secrets must resolve dynamically from the hardware TPM vault via `atlas-vault get <KEY>`. Redact secrets with `[REDACTED_BY_ATLAS_VAULT]`.
2. **Zero Disk Secrets**: Never write plaintext `.env` files. Secrets resolve in memory from `atlas-vault get <KEY>`. `VaultResolver` is a client of that command, not a TPM. Read the process environment only when `AIEN_DEV_SECRET_FALLBACK=1`. Redact secrets with `[REDACTED_BY_ATLAS_VAULT]`.
3. **Unslop Standard**: Zero em dashes (`-`) and zero en dashes (`-`). Use commas, colons, or parentheses. Do not use AI clichés or conversational filler.
4. **Pure Native Execution**: Core runtime services must compile to native Rust and Mojo. Do not introduce Node.js or Python daemons.

Expand Down
2 changes: 1 addition & 1 deletion AGENT_CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ This Specification establishes non-negotiable operational requirements for all a
---

### Article IV: Hardware Silicon Vault and Secret Redaction
1. **Dynamic In-Memory Key Resolution**: Autonomous agents are strictly forbidden from writing API keys, passwords, private tokens, or credentials to disk, logs, scratchpads, or commit histories. All secrets must resolve dynamically in memory from the hardware TPM vault (atlas-vault).
1. **Dynamic In-Memory Key Resolution**: Autonomous agents are strictly forbidden from writing API keys, passwords, private tokens, or credentials to disk, logs, scratchpads, or commit histories. Secrets resolve in memory from `atlas-vault`. The process environment is not a production source.
2. **Active Stream Redaction**: Agent output streams, logs, and subagent payloads must actively redact any string matching secret key signatures with [REDACTED_BY_ATLAS_VAULT].
3. **Data Firewall Enforcement**: Outbound peer communications must traverse the Personal Data Firewall (beacon-core), sanitizing personal file paths and sensitive host identifiers before egress.

Expand Down
4 changes: 2 additions & 2 deletions CONSTITUTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ This Constitution establishes our foundational principles, our engineering stand
### Section 4. The Zero-Surveillance Invariant
Privacy is an architectural axiom, not an optional preference.
1. Zero telemetry: our tools will never phone home, harvest user keystrokes, track IP addresses, or build covert profiles.
2. Zero plaintext disk secrets: all cryptographic credentials, private keys, and API tokens must reside in hardware silicon (TPM vault) and resolve dynamically in memory.
2. No persistent plaintext credentials. Runtime credentials resolve in memory, preferring `atlas-vault`, with hardware-backed protection where that provider actually has it. The process environment is not a production source.
3. Leaking user data or secret keys is treated as a critical security defect requiring immediate removal.

### Section 5. Open Knowledge and Sovereign Commons
Expand Down Expand Up @@ -89,7 +89,7 @@ Systems must learn and adapt continuously, but core identity must remain incorru
To ensure that only those aligned with our cause contribute:

1. **Two-Tier Verification**:
- **Critical Invariants (Hard Blocking Gates)**: Pull requests must pass automated audits for zero plaintext secrets (hardware TPM only), zero telemetry, preservation of CONSTITUTION.md, and license integrity. Violations result in automatic PR rejection.
- **Critical Invariants (Hard Blocking Gates)**: Pull requests must pass automated audits for zero plaintext secret files, zero telemetry, preservation of CONSTITUTION.md, and license integrity. Violations result in automatic PR rejection.
- **Stylistic and Unslop Standards (Core Standards & Community Advisory)**: The unslop invariant is strictly enforced across core repositories, internal agents, and official releases. For outside community pull requests, style audits provide automated formatting suggestions rather than immediate rejection.
2. **Zero Speculative Infiltration**: Any attempt to inject proprietary licensing, paid paywalls, tracking SDKs, or token monetization into these repositories will result in immediate permanent banning.
3. **Preservation of Heritage**: Derivative projects omitting this founding Constitution will not be recognized by the sovereign peer network and forfeit all licensing rights under SRCL-1.0.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ Sovereign agent runtime written in native Rust with Mojo 1.1 SIMD acceleration k
4. **Mojo 1.1 SIMD Kernels**:
Vector cosine similarity, Shannon entropy, and linear projection using Mojo SIMD vector primitives via C-ABI FFI (`libloading`).

5. **Hardware TPM Vault**:
Zero plaintext secrets on disk. In-memory secret resolution via `atlas-vault` with automatic stream redaction (`[REDACTED_BY_ATLAS_VAULT]`).
5. **Secret resolution**:
No plaintext secret files. `VaultResolver` asks `atlas-vault`, then keeps the value in memory. It is a client of that provider, not a TPM. The process environment is read only when `AIEN_DEV_SECRET_FALLBACK=1`. Output is redacted with `[REDACTED_BY_ATLAS_VAULT]`.

6. **SQLite Persistence**:
Embedded SQLite store running in Write-Ahead-Logging (WAL) mode for transactional task and message durability.
Expand Down
14 changes: 7 additions & 7 deletions docs/INNOVATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,18 @@ The `AgentEngine` implements an autonomous reasoning and execution loop:
- `write_file`: Atomically writes or updates files with parent directory creation.
- `list_dir`: Traverses directories, reporting relative paths and sizes.
- `git_status`: Inspects repository branch, staged modifications, and untracked files.
- `cortex_recall`: Queries persistent canonical memory from Spark Cortex (`atlas-memory`).
- `cortex.search`: The canonical memory tool. It is registered and not connected, so it reports unavailable instead of a fake result. `cortex_recall` is the legacy alias.

---

## 3. Hardware TPM Key Vault (`src/vault.rs`)
## 3. Secret resolution (`src/vault.rs`)

### Zero Plaintext Disk Secrets
`openclaw-rs` enforces a strict zero disk secret policy:
### No plaintext secret files
- No `.env`, `.env.local`, or configuration secret files are stored on disk.
- Cryptographic keys and tokens are stored in the host Trusted Platform Module (TPM) via `atlas-vault`.
- Secrets resolve dynamically in memory only when required for external authentication.
- Model outputs and logs are actively scanned to redact known secret signatures with `[REDACTED_BY_ATLAS_VAULT]`.
- `VaultResolver` is a client of the `atlas-vault` command. It does not open a TPM device. Hardware-backed protection is a property of that provider when the deployment has it.
- Production resolution is the in-memory cache, then `atlas-vault`. If the provider does not answer, resolution fails closed.
- `AIEN_DEV_SECRET_FALLBACK=1` is the explicit development permission to read the process environment after that.
- Model outputs and logs are scanned to redact known secret values with `[REDACTED_BY_ATLAS_VAULT]`.

---

Expand Down
2 changes: 1 addition & 1 deletion src/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ impl AgentEngine {
let home_dir = std::env::var("HOME").unwrap_or_else(|_| ".".to_string());
let user = std::env::var("USER").unwrap_or_else(|_| "sovereign".to_string());
let default_system = format!(
"You are AIEN, a sovereign native AI systems agent running on NVIDIA DGX Spark (Grace Blackwell GB10) as user {user}. Active workspaces reside strictly in {home}/workspace/ (openclaw-rs, aien-harness-publish, etc.) and {home}/atlas-prime-workspace/. Default working directory is {home}/workspace. You have native tools available to execute commands (bash_eval), inspect files (read_file, list_dir, git_status), modify files (write_file), and query memory (cortex_recall). Never run broad root filesystem scans or find /. Invoke tools directly on specific workspace targets. Adhere strictly to the unslop standard: zero em dashes and zero en dashes, no transitional fluff, and direct technical proof. When finished, provide a concise final summary.",
"You are AIEN, a sovereign native AI systems agent running on NVIDIA DGX Spark (Grace Blackwell GB10) as user {user}. Active workspaces reside strictly in {home}/workspace/ (openclaw-rs, aien-harness-publish, etc.) and {home}/atlas-prime-workspace/. Default working directory is {home}/workspace. You have native tools available to run a catalogued local command (bash_eval: git status, git diff, git log -1 --oneline, or ls), inspect files (read_file, list_dir, git_status), and modify files (write_file). Memory search is not connected. Do not claim that it is. Never run broad root filesystem scans or find /. Invoke tools directly on specific workspace targets. Adhere strictly to the unslop standard: zero em dashes and zero en dashes, no transitional fluff, and direct technical proof. When finished, provide a concise final summary.",
user = user,
home = home_dir
);
Expand Down
18 changes: 4 additions & 14 deletions src/gateway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,20 +385,10 @@ pub async fn shell_handler(
State(state): State<GatewayState>,
Json(payload): Json<ShellRequest>,
) -> Result<impl IntoResponse, (StatusCode, String)> {
if let Err(reason) =
crate::enforcement::pre_dispatch_check("bash_eval", &json!({"command": payload.command}))
{
return Ok(Json(ShellResponse {
stdout: String::new(),
stderr: reason,
exit_code: 1,
success: false,
}));
}
match state
.skills
.workspace()
.execute_shell(&payload.command, None, 15)
.dispatch_shell(&payload.command, None, 15)
{
Ok(stdout) => Ok(Json(ShellResponse {
stdout,
Expand Down Expand Up @@ -457,7 +447,7 @@ pub async fn trigger_heartbeat_handler(State(state): State<GatewayState>) -> imp

// Skills endpoints
pub async fn list_skills_handler(State(state): State<GatewayState>) -> impl IntoResponse {
let list = state.skills.list_skills();
let list = state.skills.advertised_skills();
Json(list)
}

Expand Down Expand Up @@ -536,7 +526,7 @@ async fn handle_socket(mut socket: WebSocket, state: GatewayState) {
let _ = socket.send(Message::Text(out.to_string())).await;
}
"skills_list" => {
let list = state.skills.list_skills();
let list = state.skills.advertised_skills();
let out = json!({"type": "skills_list", "skills": list});
let _ = socket.send(Message::Text(out.to_string())).await;
}
Expand Down Expand Up @@ -574,7 +564,7 @@ async fn handle_socket(mut socket: WebSocket, state: GatewayState) {
}
"shell" => {
let cmd_str = parsed.get("command").and_then(|v| v.as_str()).unwrap_or("echo shell ready");
let out = match state.skills.workspace().execute_shell(cmd_str, None, 15) {
let out = match state.skills.workspace().dispatch_shell(cmd_str, None, 15) {
Ok(stdout) => json!({
"type": "shell_output",
"stdout": stdout,
Expand Down
2 changes: 1 addition & 1 deletion src/heartbeat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ impl HeartbeatEngine {
&task.payload
};

let res_text = match self.workspace.execute_shell(cmd_to_run, None, 15) {
let res_text = match self.workspace.dispatch_shell(cmd_to_run, None, 15) {
Ok(stdout) => format!("Exit code 0: {}", stdout.trim()),
Err(e) => format!("Execution failure: {}", e),
};
Expand Down
88 changes: 86 additions & 2 deletions src/security.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,23 @@ impl WorkspaceCapability {
Ok(canonical)
}

/// Executes a shell command strictly within the validated workspace directory capability.
pub fn execute_shell(
/// The only shell entry. The membrane runs first. A command then has to
/// match a whole local form before the workspace-bound executor runs.
pub fn dispatch_shell(
&self,
command: &str,
cwd: Option<&str>,
timeout_secs: u64,
) -> Result<String, SecurityError> {
let args = serde_json::json!({ "command": command });
crate::enforcement::pre_dispatch_check("bash_eval", &args)
.map_err(SecurityError::AccessDenied)?;
admit_local_command(command)?;
self.execute_shell(command, cwd, timeout_secs)
}

/// Low-level executor. Callers use `dispatch_shell`.
pub(crate) fn execute_shell(
&self,
command: &str,
cwd: Option<&str>,
Expand Down Expand Up @@ -292,6 +307,52 @@ impl WorkspaceCapability {
}
}

/// A local command is one exact form from the catalog. The first word is not enough.
pub fn admit_local_command(command: &str) -> Result<(), SecurityError> {
if command.chars().any(|c| {
matches!(
c,
';' | '|'
| '&'
| '$'
| '<'
| '>'
| '`'
| '\\'
| '\n'
| '\r'
| '('
| ')'
| '{'
| '}'
| '!'
| '*'
| '?'
| '['
| ']'
| '\''
| '"'
)
}) {
return Err(SecurityError::AccessDenied(
"Command is not a local form. Shell joining, substitution, and quoting are not local execution.".to_string(),
));
}
let argv: Vec<&str> = command.split_whitespace().collect();
let allowed = [
["git", "status"].as_slice(),
["git", "diff"].as_slice(),
["git", "log", "-1", "--oneline"].as_slice(),
["ls"].as_slice(),
];
if allowed.iter().any(|form| form == &argv) {
return Ok(());
}
Err(SecurityError::AccessDenied(
"Command is not eligible for local shell. Local execution is only the catalogued forms: git status, git diff, git log -1 --oneline, and ls. Anything else needs a typed tool.".to_string(),
))
}

pub fn normalize_path(path: &Path) -> PathBuf {
let mut stack = Vec::new();
for comp in path.components() {
Expand Down Expand Up @@ -346,4 +407,27 @@ mod tests {
let res = cap.execute_shell("ls", Some("/etc"), 5);
assert!(res.is_err());
}

#[test]
fn local_catalog_requires_the_whole_command() {
assert!(admit_local_command("git status").is_ok());
assert!(admit_local_command("git diff").is_ok());
assert!(admit_local_command("ls").is_ok());
assert!(admit_local_command("git").is_err());
assert!(admit_local_command("git push").is_err());
assert!(admit_local_command("git status --porcelain").is_err());
assert!(admit_local_command("curl example.invalid").is_err());
assert!(admit_local_command("git status; curl example.invalid").is_err());
assert!(admit_local_command("echo $(curl example.invalid)").is_err());
}

#[test]
fn dispatch_shell_refuses_unclassified_text() {
let dir = tempdir().unwrap();
let cap = WorkspaceCapability::new(dir.path()).unwrap();
let refused = cap.dispatch_shell("echo hello", None, 5);
assert!(refused.is_err());
let allowed = cap.dispatch_shell("ls", None, 5);
assert!(allowed.is_ok());
}
}
Loading
Loading