mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 17:45:53 +01:00
fix(runner): restore remote session checkpoints
This commit is contained in:
1 parent
0bbabbaf1c
commit
42e8ac9d6f
5 files changed
+69
-5
No files matched your search
@@ -2609,6 +2609,22 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bearer_values_are_redacted_without_erasing_safe_failure_context() {
|
||||
let sanitized = crate::durable::redact_text(
|
||||
"MCP request failed: Authorization: Bearer secret-token, status 401 Unauthorized",
|
||||
);
|
||||
assert_eq!(
|
||||
sanitized,
|
||||
"MCP request failed: Authorization: Bearer [REDACTED], status 401 Unauthorized"
|
||||
);
|
||||
assert!(!sanitized.contains("secret-token"));
|
||||
assert_eq!(
|
||||
crate::durable::redact_text("Bearer first; retry used bearer second\nfailed"),
|
||||
"Bearer [REDACTED]; retry used bearer [REDACTED]\nfailed"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn durable_events_strip_binary_payloads_but_preserve_artifact_metadata() {
|
||||
let sanitized = crate::durable::sanitize_value(&json!({
|
||||
|
||||
@@ -758,10 +758,39 @@ fn redaction_key(key: &str) -> bool {
|
||||
}
|
||||
|
||||
pub fn redact_text(input: &str) -> String {
|
||||
if input.to_ascii_lowercase().contains("bearer ") {
|
||||
return "[REDACTED]".to_owned();
|
||||
const BEARER_PREFIX: &[u8] = b"bearer ";
|
||||
let bytes = input.as_bytes();
|
||||
let mut output = String::with_capacity(input.len());
|
||||
let mut cursor = 0;
|
||||
while cursor + BEARER_PREFIX.len() <= bytes.len() {
|
||||
let Some(relative_start) = bytes[cursor..]
|
||||
.windows(BEARER_PREFIX.len())
|
||||
.position(|candidate| candidate.eq_ignore_ascii_case(BEARER_PREFIX))
|
||||
else {
|
||||
break;
|
||||
};
|
||||
let start = cursor + relative_start;
|
||||
let value_start = start + BEARER_PREFIX.len();
|
||||
output.push_str(&input[cursor..start]);
|
||||
output.push_str(&input[start..value_start]);
|
||||
output.push_str("[REDACTED]");
|
||||
|
||||
let value_end = input[value_start..]
|
||||
.char_indices()
|
||||
.find_map(|(offset, character)| {
|
||||
(character.is_whitespace()
|
||||
|| matches!(character, '\"' | '\'' | ',' | ';' | ')' | ']' | '}'))
|
||||
.then_some(value_start + offset)
|
||||
})
|
||||
.unwrap_or(input.len());
|
||||
cursor = value_end;
|
||||
}
|
||||
if output.is_empty() {
|
||||
input.to_owned()
|
||||
} else {
|
||||
output.push_str(&input[cursor..]);
|
||||
output
|
||||
}
|
||||
input.to_owned()
|
||||
}
|
||||
|
||||
pub fn sanitize_value(value: &Value) -> Value {
|
||||
|
||||
@@ -586,7 +586,11 @@ mod tests {
|
||||
&json!({"item":{"id":"exec-1","type":"commandExecution","status":"completed","aggregatedOutput":output}}),
|
||||
);
|
||||
let payload = &events[0].1;
|
||||
assert_eq!(payload["output"], "[REDACTED]");
|
||||
assert_eq!(payload["outputTruncated"], true);
|
||||
assert_eq!(
|
||||
payload["output"].as_str().unwrap().as_bytes().len(),
|
||||
MAX_OUTPUT_BYTES
|
||||
);
|
||||
assert!(!payload.to_string().contains("secret"));
|
||||
assert!(payload["outputDigest"]
|
||||
.as_str()
|
||||
|
||||
@@ -298,6 +298,20 @@ describe("verified native harness backups", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const continuationExecution = {
|
||||
...backupExecution,
|
||||
binding: {
|
||||
...backupExecution.binding,
|
||||
runId: "run-2",
|
||||
executionWorkspaceId: "run-2",
|
||||
},
|
||||
} as NativeExecutionInputV1;
|
||||
expect(verifyNativeHarnessBackup({
|
||||
root,
|
||||
execution: continuationExecution,
|
||||
runnerInstanceId: "runner-1",
|
||||
})).not.toBeNull();
|
||||
|
||||
await writeFile(join(current, "codex-home", "sessions", "thread.jsonl"), "corrupt");
|
||||
expect(verifyNativeHarnessBackup({
|
||||
root,
|
||||
|
||||
@@ -923,8 +923,9 @@ function nativeHarnessEnvironmentFingerprint(
|
||||
.update(
|
||||
canonicalJson({
|
||||
companyId: execution.binding.companyId,
|
||||
agentId: execution.binding.agentId,
|
||||
issueId: execution.binding.issueId,
|
||||
normalizedSessionId: nativeSessionKey(execution),
|
||||
executionWorkspaceId: execution.binding.executionWorkspaceId,
|
||||
workspace: {
|
||||
cwd: execution.workspace.cwd,
|
||||
repoUrl: execution.workspace.repoUrl,
|
||||
|
||||
Reference in new issue
Block a user