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
14 changes: 7 additions & 7 deletions policy-engine/docs/acs-retarget.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ shapes match the legacy consumer contract.
| Gap | Issue |
| --- | --- |
| URL sourced manifests can read host environment credentials | [#20](https://github.com/responsibleai/agent-control-spec/issues/20) |
| `Limits` do not reach the bundled dispatchers | [#21](https://github.com/responsibleai/agent-control-spec/issues/21) |
| The selected `agent-control-spec` release cannot pass `Limits` to bundled dispatchers | [#21](https://github.com/responsibleai/agent-control-spec/issues/21), resolved upstream but not yet eligible for adoption |
| Telemetry sink cannot be set after `Runtime` construction | [#22](https://github.com/responsibleai/agent-control-spec/issues/22) |
| `from_url`, `policy_labels`, `validate_overlay` have no equivalent | [#23](https://github.com/responsibleai/agent-control-spec/issues/23) |
| Original binding validation gap, resolved upstream after alpha.1 | [#14](https://github.com/responsibleai/agent-control-spec/issues/14) |
Expand Down Expand Up @@ -262,10 +262,11 @@ that loading one over the network is a first class API.
- Upstream artifact diagnostics use the in-process backend and a different
shape. AGT retains its bounded, source-located OPA lint diagnostics and
explicit executable selection rather than silently changing that API.
- `Limits` does not reach the bundled dispatchers, so a tightened URL fetch budget does
not apply to a dispatch time fetch; their own defaults govern it. The engine resource
budget it also carries (snapshot size, policy input size, annotators per point) does
reach the runtime, via `Runtime::with_limits`.
- The selected `agent-control-spec` release does not expose limits-aware bundled
dispatchers. `acs_builder_set_url_fetch_limits` therefore fails closed instead of
reporting a successful configuration it cannot enforce. The C ABI retains the symbol
for compatibility until AGT can adopt the upstream fix after its supply-chain
stabilization period.

Raise these as issues or proposals on the upstream repositories rather than forking
contract semantics here. See `docs/proposals/README.md` in the agent-hooks repository for
Expand Down Expand Up @@ -319,8 +320,7 @@ What the guard does not do, all of it the same upstream gap as issue #20:
the guard. A host that needs the guard to hold across redirects must pass
`max_manifest_url_redirects: 0` (`max_url_redirects=0` in Python,
`maxRedirects: 0` in Node). The C ABI `acs_builder_from_url` fetches with
the default budget; `acs_builder_set_url_fetch_limits` runs after the fetch
and does not reach it.
the default budget and rejects attempts to configure URL fetch limits.
- A nested `extends` URL inside the fetched manifest resolves through the
upstream loader with no destination check at all.

Expand Down
42 changes: 17 additions & 25 deletions policy-engine/sdk/rust/src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ pub struct AcsBuilder {
perf_telemetry: PerfTelemetry,
enable_default_annotations: bool,
enable_default_policy: bool,
limits: Limits,
}

pub struct AcsRuntime {
Expand Down Expand Up @@ -180,7 +179,6 @@ fn builder_from_manifest(manifest: Manifest) -> *mut AcsBuilder {
perf_telemetry: PerfTelemetry::default(),
enable_default_annotations: false,
enable_default_policy: false,
limits: Limits::default(),
}))
}

Expand Down Expand Up @@ -518,43 +516,37 @@ pub unsafe extern "C" fn acs_builder_set_perf_telemetry(
})
}

/// Record URL fetch limits on the builder. `max_bytes` caps a fetched body,
/// `timeout_ms` bounds each request, and `max_redirects` caps the redirect
/// chain. A `max_bytes` or `timeout_ms` of 0 keeps the built in default for
/// that field; `max_redirects` is applied as given so 0 forbids redirects.
/// Report that configuring bundled-dispatcher URL fetch limits is unavailable.
///
/// The pre-retarget engine threaded these into its bundled dispatchers for
/// `system_prompt_url` and `bundle_url` fetches. Those fields were removed
/// (a manifest declaring them is rejected at load) and `agent-control-spec`
/// 0.4.0-alpha.3 constructs its dispatchers without limits, so this setter
/// currently reaches nothing; it is kept so the ABI stays stable while
/// upstream issue #21 is open. `acs_builder_from_url` fetches before the
/// builder exists and uses the default budget.
/// `agent-control-spec` 0.4.0-alpha.3 does not expose a way to pass limits to
/// its bundled dispatchers. Returning an error prevents callers from relying
/// on a budget that cannot be enforced. The ABI symbol remains available for
/// compatibility until AGT can adopt an eligible upstream release with the
/// limits-aware dispatcher constructors.
///
/// # Safety
/// `b` must be a live builder returned by ACS and not concurrently mutated. If
/// `err` is non-null it must be writable.
#[no_mangle]
pub unsafe extern "C" fn acs_builder_set_url_fetch_limits(
b: *mut AcsBuilder,
max_bytes: u64,
timeout_ms: u64,
max_redirects: u32,
_max_bytes: u64,
_timeout_ms: u64,
_max_redirects: u32,
err: *mut *mut c_char,
) -> i32 {
ffi_guard!(code_with_err, err, -1, {
let Some(builder) = (unsafe { b.as_mut() }) else {
if b.is_null() {
unsafe { write_err(err, "null builder") };
return -1;
};
if max_bytes != 0 {
builder.limits.max_manifest_url_bytes = max_bytes as usize;
}
if timeout_ms != 0 {
builder.limits.manifest_url_timeout_ms = timeout_ms;
}
builder.limits.max_manifest_url_redirects = max_redirects as usize;
0
unsafe {
write_err(
err,
"URL fetch limits are unavailable: agent-control-spec 0.4.0-alpha.3 cannot apply them to bundled dispatchers",
)
};
-1
})
}

Expand Down
27 changes: 27 additions & 0 deletions policy-engine/sdk/rust/tests/upstream_compatibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,33 @@ intervention_points:
id: rule
"#;

#[test]
fn ffi_rejects_url_fetch_limits_the_pinned_engine_cannot_enforce() {
use agent_control_specification::ffi;
use std::ffi::{CStr, CString};

let manifest = CString::new(MANIFEST).unwrap();
let mut error = std::ptr::null_mut();
unsafe {
let builder = ffi::acs_builder_from_yaml(manifest.as_ptr(), &mut error);
assert!(!builder.is_null());
assert!(error.is_null(), "builder construction failed");

assert_eq!(
ffi::acs_builder_set_url_fetch_limits(builder, 4096, 1_000, 0, &mut error),
-1
);
assert!(!error.is_null(), "unsupported limits must report an error");
let message = CStr::from_ptr(error).to_string_lossy();
assert!(
message.contains("cannot apply them to bundled dispatchers"),
"unexpected error: {message}"
);
ffi::acs_free_string(error);
ffi::acs_builder_free(builder);
}
}

#[test]
fn engine_release_and_manifest_grammar_have_distinct_versions() {
const LEGACY_ARRAY: [&str; 1] = SUPPORTED_MANIFEST_VERSIONS;
Expand Down
Loading