(
state: &Arc<ServerState>,
sandbox_id: &str,
sandbox_name: &str,
chunk_id: &str,
source: &str,
resolved_from: &str,
)
| 881 | } |
| 882 | |
| 883 | async fn auto_approve_chunk( |
| 884 | state: &Arc<ServerState>, |
| 885 | sandbox_id: &str, |
| 886 | sandbox_name: &str, |
| 887 | chunk_id: &str, |
| 888 | source: &str, |
| 889 | resolved_from: &str, |
| 890 | ) -> Result<(), Status> { |
| 891 | // Same gate the human-driven approve paths apply: if a global policy is |
| 892 | // active, sandbox-scoped chunk approvals are meaningless because |
| 893 | // `GetSandboxConfig` prefers the global policy. Auto-approving here |
| 894 | // would persist a sandbox revision that the runtime silently ignores |
| 895 | // and leave a misleading "approved" chunk in the table. Bail before |
| 896 | // touching state; the calling site logs this as `warn!` and leaves the |
| 897 | // chunk pending. |
| 898 | require_no_global_policy(state).await?; |
| 899 | |
| 900 | let chunk = state |
| 901 | .store |
| 902 | .get_draft_chunk(chunk_id) |
| 903 | .await |
| 904 | .map_err(|e| Status::internal(format!("fetch chunk failed: {e}")))? |
| 905 | .ok_or_else(|| Status::not_found("chunk not found"))?; |
| 906 | |
| 907 | // The chunk may have been superseded or rejected by something else |
| 908 | // between persist and auto-approve. Only approve from a pending state. |
| 909 | if chunk.status != "pending" { |
| 910 | return Ok(()); |
| 911 | } |
| 912 | |
| 913 | let (version, hash) = merge_chunk_into_policy(state.store.as_ref(), sandbox_id, &chunk).await?; |
| 914 | let chunk_summary = summarize_draft_chunk_rule(&chunk)?; |
| 915 | |
| 916 | let now_ms = current_time_ms(); |
| 917 | state |
| 918 | .store |
| 919 | .update_draft_chunk_status(chunk_id, "approved", Some(now_ms), None) |
| 920 | .await |
| 921 | .map_err(|e| Status::internal(format!("update chunk status failed: {e}")))?; |
| 922 | |
| 923 | state.sandbox_watch_bus.notify(sandbox_id); |
| 924 | |
| 925 | let source_label = if source.is_empty() { |
| 926 | "unspecified" |
| 927 | } else { |
| 928 | source |
| 929 | }; |
| 930 | emit_gateway_policy_auto_approve_audit_log( |
| 931 | sandbox_id, |
| 932 | sandbox_name, |
| 933 | format!( |
| 934 | "auto-approved: no new prover findings (source={source_label}) — chunk {chunk_id}: {chunk_summary}" |
| 935 | ), |
| 936 | version, |
| 937 | &hash, |
| 938 | source_label, |
| 939 | resolved_from, |
| 940 | ); |
no test coverage detected