Skip to content

feat(apex): establish authenticated runtime trust boundary - #3

Draft
kratosboom wants to merge 3 commits into
apex/orchestratorfrom
apex/trust-boundary
Draft

feat(apex): establish authenticated runtime trust boundary#3
kratosboom wants to merge 3 commits into
apex/orchestratorfrom
apex/trust-boundary

Conversation

@kratosboom

Copy link
Copy Markdown

STACKED ON PR #2
CLOSES RESIDUAL SECURITY FINDINGS #4#7#8
NO CODEX CORE INTEGRATION
NO PRODUCTION CHANGE
NO MERGE

@kratosboom
kratosboom marked this pull request as draft August 22, 2026 08:22

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:b7d33bd824

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +242 to +244
EvidenceProvenance::TrustedExecution { receipt } => {
matches!(kind, EvidenceKind::Test | EvidenceKind::Ci)
&& receipt.outcome() == ExecutionOutcome::Pass

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject local execution receipts as CI evidence

A caller can run any successful local command—even /bin/true—and submit the receipt as EvidenceKind::Ci, because every passing TrustedExecutionReceipt is treated as authoritative for both Test and CI. This lets the Ready gate pass without authenticated CI, contradicting the new runtime-trust contract that external CI remains unavailable; restrict LocalCommand receipts to Test evidence or bind receipts to an authenticated CI executor/provider.

Useful? React with 👍 / 👎.

Comment on lines +351 to +355
Ok(TrustedExecutionReceipt {
executor: ExecutorKind::LocalCommand,
task_id: task_id.to_owned(),
task_revision,
source_revision: source.source_revision().to_owned(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Bind command execution to immutable verified source

When the command or another process changes the worktree after the single pre-spawn is_current() check, the command can execute against content other than the verified commit while this code still emits a Pass receipt naming the old SHA. A command can even restore the files before exiting, defeating a simple post-run cleanliness check, so trusted execution should use an immutable checkout/snapshot rather than the mutable verified worktree.

Useful? React with 👍 / 👎.

Comment on lines +501 to +509
pub fn submit_trusted_execution_evidence(
&mut self,
principal: impl Into<String>,
receipt: &TrustedExecutionReceipt,
subject: &EvidenceSubject,
kind: EvidenceKind,
status: EvidenceStatus,
detail: impl Into<String>,
) -> Result<(), OrchestrationError> {
self.require_subject(subject)?;
let role = match kind {
EvidenceKind::Ci => EvidenceRole::Ci,
_ => {
return Err(OrchestrationError::ProvenanceRequired);
}
};
let principal = principal.into();
if principal.is_empty() {
return Err(OrchestrationError::ProvenanceRequired);
}
let record = EvidenceRecord::with_provenance(
kind,
status,
subject.clone(),
detail,
EvidenceProvenance::TrustedSystem {
id: principal,
role,
},
)
.map_err(|_| OrchestrationError::ProvenanceRequired)?;
let record = EvidenceRecord::from_trusted_execution(kind, subject.clone(), detail, receipt)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add integration coverage for the trust flow

The cross-crate agent/release flow introduced here has only per-module unit tests, leaving the full behavior untested: authenticate and restore a task snapshot, verify its Git source, execute a trusted test, submit its receipt, and confirm release decisions change when the source or receipt becomes invalid. Add an integration test covering that end-to-end boundary as required for agent-logic changes.

AGENTS.md reference: AGENTS.md:L112-L120

Useful? React with 👍 / 👎.

Comment on lines +363 to +364
#[cfg(test)]
mod tests {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Move the new tests into a sibling test file

This newly introduced crate defines its new test module inline in the implementation file. Move it to a descriptive sibling *_tests.rs file and reference it with an explicit #[path = "..."] attribute.

AGENTS.md reference: AGENTS.md:L169-L178

Useful? React with 👍 / 👎.

Comment threadapexcode/Cargo.toml
"apex-task-state",
"apex-evidence",
"apex-orchestrator",
"apex-runtime-trust",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Split the trust-boundary change into reviewable stages

This non-mechanical security change totals 1,445 changed lines and combines authenticated snapshot restoration, the Git/command trust crate, evidence provenance, and orchestrator wiring. Split it by landing the apex-task-state authenticated snapshot API and dependencies first, followed by apex-runtime-trust, evidence integration, and orchestrator wiring, so each trust invariant can be reviewed independently.

AGENTS.md reference: AGENTS.md:L125-L131

Useful? React with 👍 / 👎.

Comment on lines +170 to +172
let git_root = self.git(repository_root, &["rev-parse", "--show-toplevel"])?;
let git_root =
std::fs::canonicalize(git_root.trim()).map_err(|_| TrustError::NotGitRepository)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve repository paths as operating-system strings

Converting git rev-parse --show-toplevel output through a lossy UTF-8 String and then calling trim() rejects valid Unix repositories whose paths contain non-UTF-8 bytes or end in whitespace/newlines. Handle the path as raw OS bytes or avoid round-tripping it through command output so valid platform paths remain verifiable.

AGENTS.md reference: AGENTS.md:L317-L322

Useful? React with 👍 / 👎.

Comment threadapexcode/apex-runtime-trust/src/lib.rs
Comment on lines +184 to +188
if !self
.git(
repository_root,
&["status", "--porcelain", "--untracked-files=all"],
)?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Verify tracked bytes instead of trusting Git status

A clean git status does not prove that tracked on-disk bytes equal HEAD: skip-worktree or assume-unchanged index flags, sparse checkouts, and ignored submodule changes can hide modified or absent tracked content from this command. The verifier can therefore mint a VerifiedSource while the runner reads bytes not represented by source_revision; compare or hash the checked-out tracked content against the commit tree rather than relying on status alone.

Useful? React with 👍 / 👎.

Comment on lines +331 to +335
if let Some(status) = child
.try_wait()
.map_err(|error| TrustError::ExecutionFailed(error.to_string()))?
{
let outcome = if status.success() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enforce the deadline before accepting command success

The polling loop checks try_wait() before checking the deadline, so a process that exits after its timeout but before the next 10 ms poll is reported as Pass rather than Unavailable; scheduler delays can widen this overrun further. Use a timeout-aware wait or otherwise ensure completion after the deadline cannot mint a successful trusted receipt.

Useful? React with 👍 / 👎.

Comment on lines +331 to +334
if let Some(status) = child
.try_wait()
.map_err(|error| TrustError::ExecutionFailed(error.to_string()))?
{

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clean up the child when post-spawn waiting fails

If try_wait() returns an OS error, execute propagates immediately, but dropping std::process::Child neither terminates nor waits for the process. The supposedly bounded command can therefore continue running after ExecutionFailed is returned; use a cleanup guard that kills and reaps the child on every error after a successful spawn.

Useful? React with 👍 / 👎.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@kratosboom