astrid-runtime/astrid · error

capsule install authority was not approved

Error message

capsule install authority was not approved

What it means

When no automated or flag-based approval applies, authority_decision prints the capsule's provenance, signer, content digest, and any new capability expansions, then asks 'Approve this exact install once? [y/N]'. If the operator's stdin answer is anything other than y/yes (case-insensitive), the install is aborted with this error. It is the normal refusal outcome of the interactive consent gate, not a malfunction.

Source

Thrown at crates/astrid-cli/src/commands/capsule/install/authority.rs:78

        for expansion in &inspection.capability_expansions {
            let semantic = semantic_expansion(expansion);
            eprintln!("    - {}", semantic.action);
            if !semantic.scope.is_empty() {
                eprintln!("      Scope: {}", semantic.scope.join("; "));
            }
            eprintln!("      Impact: {}", semantic.impact);
        }
    }
    eprint!("Approve this exact install once? [y/N] ");
    std::io::Write::flush(&mut std::io::stderr())?;
    let mut answer = String::new();
    std::io::stdin().read_line(&mut answer)?;
    if matches!(answer.trim().to_ascii_lowercase().as_str(), "y" | "yes") {
        Ok(AuthorityDecision::ExplicitApproval {
            content_digest: inspection.content_digest.clone(),
        })
    } else {
        bail!("capsule install authority was not approved")
    }
}

pub(super) fn daemon_install_authority(
    source: &str,
    principal: &astrid_core::PrincipalId,
    prompt: &ManualInstallOptions,
) -> anyhow::Result<CapsuleInstallAuthority> {
    let home = AstridHome::resolve()?;
    let path = Path::new(source.strip_prefix("file://").unwrap_or(source));
    let inspection = if path.is_file() {
        inspect_archive_for_principal_with_layout(
            path,
            &home,
            principal,
            false,
            crate::workspace_layout::current(),
        )?

View on GitHub (pinned to affd8760f4)

Solutions

  1. Re-run the install interactively and answer `y` or `yes` at the 'Approve this exact install once?' prompt if you trust the artifact.
  2. Ensure stdin is a TTY or an open pipe; EOF (e.g. `cmd < /dev/null` or nohup without stdin) is treated as refusal.
  3. For scripted trusted installs, pass `--approve-untrusted` (after reviewing the digest) instead of relying on piped input.
  4. Verify the capsule's signer and content digest printed before the prompt; if they are unexpected, keep declining and investigate the source.
  5. For operator distribution scenarios, use the batch mode path which grants OperatorDistribution authority without prompting.

Example fix

# before (non-interactive stdin, instant refusal)
echo -n | astrid capsule install ./x.capsule
# after
printf 'y\n' | astrid capsule install ./x.capsule   # or run interactively / use --approve-untrusted
Defensive patterns

Strategy: try-catch

Validate before calling

# guard: only run when interactive, or pre-approve via flag
[ -t 0 ] || { echo "non-interactive stdin: pass --approve-untrusted"; exit 1; }

Try / catch

match authority_decision(&inspection, &prompt) {
    Ok(decision) => install_with(decision),
    Err(e) if e.to_string().contains("not approved") => eprintln!("install declined by operator"),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Interactive capsule install reaches the approval prompt (non-LocalRuntime provenance, not BATCH_MODE, no --approve-untrusted, no --yes) and stdin yields a line that does not trim/lowercase to "y" or "yes" — e.g. pressing Enter, typing "n", "no", or EOF (empty read, as when stdin is /dev/null or a closed pipe).

Common situations: User intentionally declines an untrusted capsule; running the command in a non-interactive shell where stdin returns EOF immediately, so the read yields an empty string and counts as refusal; scripting around the prompt by piping nothing; user misreads the prompt and types "no" expecting a different flow.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/b3f0eca144998e4b. Report an issue: GitHub.