Skip to content

Commit 1d9d89c

Browse files
nficanodependabot[bot]cursoragent
authored
Fix audit findings: bugs, spec-conformance, security, docs (#37-76)
* Bump the dotnet-dependencies group with 2 updates Bumps Microsoft.Extensions.Hosting.Abstractions from 9.0.0 to 10.0.8 Bumps Microsoft.NET.Test.Sdk from 18.5.1 to 18.6.0 --- updated-dependencies: - dependency-name: Microsoft.Extensions.Hosting.Abstractions dependency-version: 10.0.8 dependency-type: direct:production update-type: version-update:semver-major dependency-group: dotnet-dependencies - dependency-name: Microsoft.NET.Test.Sdk dependency-version: 18.6.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dotnet-dependencies ... Signed-off-by: dependabot[bot] <support@github.com> * chore(deps): bump codecov/codecov-action from 6.0.1 to 7.0.0 Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 6.0.1 to 7.0.0. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](codecov/codecov-action@e79a696...fb8b358) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * fix: idempotency, cancel authority, client robustness, lease boundary (#71, #72, #73, #74, #75, #76) - #71 idempotent job.submit replay no longer re-runs the agent (skip Resolve/RunAsync on replay) - #72 lease glob "/prefix/**" keeps the path-boundary separator so siblings are not authorized - #73 server-rejected job.submit/list_jobs now fault the awaiting client instead of hanging - #74 cancel authority is session-scoped (fail-closed), not principal-scoped - #75 add job.cancelled ack and JOB_NOT_FOUND for unknown jobs - #76 populate session.jobs last_event_seq from a per-job high-water mark Co-authored-by: Cursor <cursoragent@cursor.com> * fix: spec-conformance, concurrency, and security audit fixes (#37, #38, #39, #40, #41, #42, #43, #45, #46, #47, #67, #68) Runtime / spec-conformance: - #37 root running jobs at a runtime-scoped token so session teardown (heartbeat loss, graceful close, transport drop) no longer terminates in-flight jobs (spec §6.4, §6.7) - #41 add session.close/session.closed wire types; the runtime acks a graceful close with session.closed (session.bye kept as a deprecated alias) (spec §6.7) - #40 dispatch now surfaces session.error{INTERNAL_ERROR} for unexpected exceptions (spec §12) - #46 advertise model.use independently of credential provisioning (spec §9.7) Event delivery / ordering: - #39 serialize event_seq assignment with the outbound enqueue via a per-session emit gate so wire order is strictly monotonic under concurrent emitters (spec §8.3) - #38 subscriber fan-out is back-pressure-aware: on a full channel the subscription is torn down deterministically instead of silently dropping an already-sequenced event (spec §8.3) - #44 make the subscribe history/live-fan-out boundary exact via an atomic register+snapshot and a per-job event index, so a mid-stream subscriber sees each event exactly once (spec §7.6) Authorization / security: - #42 gate lease operations on remaining budget (BUDGET_EXHAUSTED) before the pattern check (spec §9.6) - #43 deny-by-default for uncovered tool.call/agent.delegate, with an explicit PermissiveUnleasedOperations opt-in (spec §9.3) - #45 list_jobs fails closed: an empty/absent principal sees only what the policy permits (spec §6.6, §14) Performance / correctness: - #67 keyset pagination over (created_at, job_id): stable ties and page work bounded to limit+1 - #68 AgentRegistry no longer exposes its mutable version dictionary; ToInventory snapshots under lock - #47 client detects event_seq gaps and raises a broken-session signal (spec §8.3) Co-authored-by: Cursor <cursoragent@cursor.com> * test: cover audit fixes; update samples/recipes for deny-by-default leases - Add unit tests for the budget authorization gate (#42) and AgentRegistry concurrency (#68). - Add integration tests for job survival across session teardown (#37), session.close/closed (#41), INTERNAL_ERROR on unexpected dispatch failure (#40), fail-closed empty-principal listing (#45), model.use advertisement (#46), keyset pagination stability (#67), deny-by-default tool.call (#43), strictly-monotonic event_seq under concurrent emitters (#39), exactly-once subscribe boundary (#44), and client event_seq gap detection (#47). - Grant tool.call/agent.delegate leases in the CostBudget, Delegate, and multi-agent-budget samples/recipes so they remain runnable under deny-by-default (#43); enable permissive mode in the event round-trip test which exercises event kinds rather than lease enforcement. Co-authored-by: Cursor <cursoragent@cursor.com> * docs: fix audit documentation issues (#48-66); format AuditFixesTests Correct XML comments, guides, OTel/conformance tables, and README for all open docs audit findings. Fix dotnet format whitespace in integration tests. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 43c62d3 commit 1d9d89c

55 files changed

Lines changed: 1533 additions & 201 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ jobs:
9595
# Non-blocking: a Codecov outage must not break CI.
9696
- name: Upload coverage to Codecov
9797
# codecov/codecov-action v6.0.1
98-
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
98+
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
9999
with:
100100
fail_ci_if_error: false
101101
flags: unittests

CONFORMANCE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ Status legend: Implemented ✅ · Partial 🚧 · Not implemented ⛔.
6969
| ---- | ----------- | ------ | ----- |
7070
| §10 | `delegate` event kind on parent's `job.event` stream || `JobContext.DelegateAsync` |
7171
| §11 | `trace_id` propagation; OTel span attrs || `TraceAttributes`, `ArcpTracing.WithTracing` |
72-
| §11 (v1.1) | Span attrs `arcp.lease.expires_at`, `arcp.budget.remaining` | | `TraceAttributes` |
72+
| §11 (v1.1) | Span attrs `arcp.lease.expires_at`, `arcp.budget.remaining` | | Not emitted by `ArcpTracing` |
7373
| §12 | 15 canonical error codes with retryable booleans || `ErrorCode.All`, `ErrorCode.IsRetryable` |
7474

7575
## Test cross-reference

Directory.Packages.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<ItemGroup Label="Runtime">
99
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.8" />
1010
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.8" />
11-
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.0" />
11+
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.8" />
1212
<PackageVersion Include="Microsoft.Extensions.Options" Version="10.0.8" />
1313
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.2.0" />
1414
<PackageVersion Include="Ulid" Version="1.4.1" />
@@ -23,7 +23,7 @@
2323
</ItemGroup>
2424

2525
<ItemGroup Label="Test">
26-
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
26+
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
2727
<PackageVersion Include="xunit" Version="2.9.3" />
2828
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
2929
<PackageVersion Include="FluentAssertions" Version="8.10.0" />

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ await using var client = await ArcpClient.ConnectAsync(transport, new ArcpClient
105105

106106
var sessionId = client.SessionId;
107107
var resumeToken = client.ResumeToken;
108-
var effective = client.EffectiveFeatures; // intersection of client/runtime hello.features
108+
var effective = client.EffectiveFeatures; // intersection of hello.features and welcome.features
109109
110110
// ... transport drops; track the last seq your reader observed ...
111111
var lastSeq = client.LastReceivedSeq;

docs/architecture.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
| `Arcp.Runtime` | `ArcpServer`, `JobManager`, `LeaseManager`, `SessionState` — the side that runs them. |
1010
| `Arcp.AspNetCore` | Mounts a runtime on Kestrel via `IEndpointRouteBuilder.MapArcp("/arcp")`. |
1111
| `Arcp.Otel` | Wraps `ITransport` with `ActivitySource`-based OTel instrumentation. |
12-
| `Arcp.Hosting` | Registers a runtime in `IHostedService` for non-ASP.NET workers. |
12+
| `Arcp.Hosting` | Registers `ArcpServer` in DI via `AddArcpRuntime` for non-ASP.NET workers. |
1313
| `Arcp.Cli` | `arcp serve` / `arcp submit` / `arcp version` executable. |
1414
| `Arcp` | Umbrella meta-package — `dotnet add package Arcp` pulls Core + Client + Runtime. |
1515

@@ -37,12 +37,12 @@ Every message is a JSON object envelope:
3737

3838
Unknown top-level fields are preserved verbatim in
3939
`Envelope.Extensions` (`Dictionary<string, JsonElement>`), so
40-
vendor-extension hints round-trip without loss (spec §5.1).
40+
vendor-extension hints round-trip without loss (spec §5).
4141

4242
## Versioning
4343

4444
The SDK follows SemVer strictly. The `arcp` wire version field
45-
(`"1.1"`) is fixed in `Arcp.Core.WireVersion.Current`. Adding a
45+
defaults to `"1.1"` on `Envelope.Arcp` (also exposed as `Arcp.ArcpInfo.ProtocolVersion`). Adding a
4646
public member is a minor bump; changing a signature is a major bump.
4747
One minor deprecation cycle (`[Obsolete]`) before removal. See the
4848
[style guide](./style-guide.md#14-versioning--compatibility).

docs/conformance.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ Opt out of features on either peer:
6060
```csharp
6161
new ArcpClientOptions
6262
{
63-
Features = new FeatureSet(["heartbeat", "ack"]), // drop the rest
63+
Features = new[] { FeatureFlags.Heartbeat, FeatureFlags.Ack }, // drop the rest
6464
};
6565
```
6666

docs/guides/errors.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ Agents can produce errors by throwing:
9090
```csharp
9191
server.RegisterAgent("strict", async (ctx, ct) =>
9292
{
93-
if (!ctx.Lease.Contains(LeaseNamespaces.FsRead))
93+
if (ctx.Lease.Get(LeaseNamespaces.FsRead).Count == 0)
9494
throw new PermissionDeniedException("fs.read required");
9595

9696
// ...

docs/guides/job-events.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ server.RegisterAgent("researcher", async (ctx, ct) =>
2727
await ctx.StatusAsync("starting", "Fetching data...", ct);
2828

2929
await ctx.ToolCallAsync("fetch", callId: "c1",
30-
args: new { url = "https://api.example.com/data" }, ct);
30+
args: new { url = "https://api.example.com/data" }, cancellationToken: ct);
3131
var data = /* ... */ "";
32-
await ctx.ToolResultAsync("c1", result: data, ct);
32+
await ctx.ToolResultAsync("c1", result: data, cancellationToken: ct);
3333

34-
await ctx.ProgressAsync(current: 1, total: 3, message: "fetched", ct);
34+
await ctx.ProgressAsync(current: 1, total: 3, message: "fetched", cancellationToken: ct);
3535

3636
await ctx.LogAsync("info", "Processing ...", ct);
3737
await ctx.MetricAsync("cost.inference", 0.012, unit: "USD", cancellationToken: ct);
@@ -40,7 +40,7 @@ server.RegisterAgent("researcher", async (ctx, ct) =>
4040
uri: "s3://bucket/report.pdf",
4141
contentType: "application/pdf",
4242
byteSize: 42_000,
43-
ct: ct);
43+
cancellationToken: ct);
4444

4545
return new { status = "done" };
4646
});

docs/guides/leases.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ server.RegisterAgent("file-writer", async (ctx, ct) =>
4747
ctx.Lease,
4848
ctx.LeaseConstraints,
4949
LeaseNamespaces.FsWrite,
50-
path: "/workspace/src/output.cs");
50+
pattern: "/workspace/src/output.cs");
5151
}
5252
catch (PermissionDeniedException ex)
5353
{

docs/guides/observability.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ constants.
4141
| Name | Purpose |
4242
| ----------------- | -------------------------------------------------- |
4343
| `Arcp.Transport` | One span per envelope (send and receive). |
44-
| `Arcp.Runtime` | Runtime-internal spans (dispatch, agent run). |
44+
| `Arcp.Runtime` | Application spans you start manually (e.g. delegation). |
4545
4646
## Span shape
4747
@@ -66,10 +66,6 @@ For each envelope, the wrapper:
6666
| `arcp.job_id` | envelope `job_id` |
6767
| `arcp.trace_id` | envelope `trace_id` |
6868
| `arcp.event_seq` | envelope `event_seq` |
69-
| `arcp.agent` | `payload.agent` (on submit / accept) |
70-
| `arcp.lease.capabilities` | comma-joined lease keys |
71-
| `arcp.lease.expires_at` | ISO 8601 string (v1.1) |
72-
| `arcp.budget.remaining` | JSON-stringified currency map (v1.1) |
7369
7470
## Use with ASP.NET Core
7571

0 commit comments

Comments
 (0)