feat(sdk/go): add Go SDK foundation, types, and sandbox client (A) - #2271
feat(sdk/go): add Go SDK foundation, types, and sandbox client (A)#2271rhuss wants to merge 21 commits into
Conversation
Principal Engineer Review — Go SDK foundation (A)Reviewed by checking out the branch and reading every non-generated file. Blocking1. Dead code will fail the project's own lint gate —
|
- Make scheme parsing drive transport selection: http:// uses plaintext gRPC, https:// or no scheme uses TLS. Add regression tests. - Add Resources and DriverConfig fields to SandboxTemplate and update both converter directions (SandboxFromProto/SandboxSpecToProto). - Regenerate proto bindings from current canonical proto sources to eliminate drift (SigV4/MCP fields, params matchers, reserved fields). - Run gofmt/goimports on all handwritten Go files. Signed-off-by: Roland Huß <rhuss@redhat.com>
russellb
left a comment
There was a problem hiding this comment.
[codex:gpt-5.5] Finding 1: The Go SDK still drops active sandbox policy fields from the handwritten types/converters. The synced proto includes credential_signing, signing_service, signing_region, json_rpc_max_body_bytes, mcp, and params on L7 allow/deny rules, but PolicyNetworkEndpoint, L7Allow, L7DenyRule, and the converters omit them. Since Create sends SandboxSpecToProto, Go clients cannot express current SigV4/MCP/JSON-RPC policy controls, and server-returned policies lose these fields on round-trip. Please add SDK fields and bidirectional converter coverage for every current proto policy field. Refs: sdk/go/openshell/v1/types/network_policy.go:19, sdk/go/openshell/v1/internal/converter/network_policy.go:65, proto/sandbox.proto:131, proto/sandbox.proto:211.
[codex:gpt-5.5] Finding 2: mapToStruct ignores structpb.NewStruct errors for SandboxTemplate.Resources and DriverConfig. Invalid UTF-8 keys or unsupported map[string]any values make NewStruct return nil, err, but the SDK silently sends nil, so user-provided template config can disappear without an error. Please make sandbox spec conversion fallible, validate before CreateSandbox, or expose a safer typed representation, and add tests for invalid values. Refs: sdk/go/openshell/v1/internal/converter/copy.go:60, sdk/go/openshell/v1/internal/converter/sandbox.go:170, sdk/go/openshell/v1/sandbox_client.go:28.
|
My agent's response to #2271 (comment). Most of the things are because of this artificial split to get the PRs down to something more consumable (which was also important as I hight some size limits for code agent's review when I dropped it). But thank you very much for jumping on it, I've addressed the comments (and delayed some until we get the full combo in) Thanks for the review. Here is my assessment, classifying each finding by root cause: Already addressed (in a prior fix commit
Fixed now (commit
Deferred to later PRs (expected from the A-F split):
Accepted as low-priority (not blocking):
|
Sounds good. I figured some of it would be off, but that your agent would sort it out. :) |
Move Go SDK mise configuration from standalone sdk/go/mise.toml into the project's centralized pattern: - Add Go tools (go, golangci-lint, protoc-gen-go, protoc-gen-go-grpc) to root mise.toml [tools] section - Create tasks/go.toml with all SDK tasks using go: namespace prefix and dir=sdk/go for working directory - Update sdk/go/Makefile to reference namespaced task names - Update proto:sync default path for monorepo layout Addresses review feedback from drew on PR NVIDIA#2271 regarding mise convention alignment. Signed-off-by: Roland Huß <rhuss@redhat.com>
Review verdict: Request changesPR #2271 (#2271) has a sound overall structure, but I found four merge-blocking issues:
Additional cleanup:
Validation: go test ./..., go test -race ./..., and go vet ./... all passed locally. The typed sub-client architecture, proto/domain separation, and sandbox test coverage are otherwise strong. |
|
Thanks for the thorough review. Addressed 3 of the 4 code findings in ad76876: [P2] RefreshStrategy missing AWS STS - Added [P2] WaitReady bypasses typed errors - Added [P2] Invalid template maps silently discarded - Changed [P1] CI wiring - This is tracked separately in PR #2344 (SDK proto sync CI). The root Re: gofmt/goimports and Signed-off-by - will clean up in the next push. |
- Add RefreshStrategyAWSStsAssumeRole to match proto enum value 6, fulfilling the "all domain types upfront" contract - Wrap context.DeadlineExceeded and context.Canceled in StatusError so IsDeadlineExceeded() and IsCancelled() helpers work correctly - Return error from mapToStruct/SandboxSpecToProto instead of silently discarding structpb.NewStruct failures on invalid template maps Signed-off-by: Roland Huss <rhuss@redhat.com>
ad76876 to
163589a
Compare
|
• Partially fixed. Commit 163589a (163589a) resolves three of four principal findings: Finding Status Validation passed: go test ./..., race tests, and go vet ./.... Still blocking approval:
Verdict: keep Request changes until CI integration and formatting are fixed; the three implementation fixes themselves look correct. |
- Wire go:ci into root ci task so SDK is tested in repository CI - Fix gofmt formatting on converter files - Add goimports to mise.toml tools - Add coverage.out to .gitignore - Add Go SDK section to AGENTS.md and CONTRIBUTING.md - Add regression tests for context-error wrapping (IsDeadlineExceeded, IsCancelled) and invalid template map rejection - Remove panic from SandboxToProto, return error instead Signed-off-by: Roland Huss <rhuss@redhat.com>
|
Addressed all remaining items in 41b2a4a:
Test count: 146 (was 144). All pass with Still outstanding (historical, cannot fix without interactive rebase):
|
|
Re-review: the original functional issues are fixed. Regression tests cover them, go test -race ./... passes, and formatting/diff checks are clean. One remaining concern: goimports is set to latest ( Line 32 in 41b2a4a Also, the latest head now includes root CI wiring despite the earlier deferral. AI attribution/sign-off cleanup on squash is fine. Verdict: code fixes look ready; one small tooling change requested. |
Pin goimports to 0.48.0 instead of "latest" and regenerate mise.lock to include the new entry. Signed-off-by: Roland Huss <rhuss@redhat.com>
|
Blockers
NewClient(http:// + StaticToken) err=grpc connect: grpc: the credentials require transport level security NewClient never returns a usable client. This breaks the entire local-dev and k3d onboarding path — you cannot authenticate to a dev gateway at all.
Go clients can't express SigV4 re-signing, MCP options, or JSON-RPC body limits, and a Get → modify → Create round-trip strips them. Silently dropping credential_signing is a security-relevant downgrade, not just a gap.
Should fix
Minor
What's good The proto-free types package with an enforced boundary is the right call and well executed. Deep-copy at every converter boundary, closeOnce on Close, and the double-checked-locking refresh with stale-token fallback and structured logging are all solid. The buf migration Findings 1, 2, and 3 are the ones I'd consider merge-blocking on their own — 1 because the SDK can't authenticate anywhere but production, and 3 because it drops a security control silently. |
Align TLS.Insecure semantics with the Rust SDK: Insecure: true now uses TLS with InsecureSkipVerify (skip cert verification) instead of switching to plaintext. Only the http:// scheme triggers plaintext. This fixes token auth against dev/k3d gateways: StaticToken and RefreshableToken require transport security, which real TLS (even with InsecureSkipVerify) satisfies, but plaintext does not. For http:// + token auth (dev gateways without TLS), wrap the auth provider to override RequireTransportSecurity, matching the Rust SDK's behavior where http:// accepts any auth mode. Transport decision table (matches Rust SDK crates/openshell-sdk): http:// + any TLS config -> plaintext (TLS config ignored) https:// + Insecure: true -> TLS, skip cert verify https:// + Insecure: false -> TLS, full verification no scheme -> same as https:// Signed-off-by: Roland Huss <rhuss@redhat.com>
Add 6 previously silently dropped fields to the network policy types and converters, preventing security-relevant data loss on round-trip: NetworkEndpoint fields 19-23: - CredentialSigning: SigV4 re-signing mode - SigningService: AWS service name for SigV4 - SigningRegion: AWS region override for SigV4 - JsonRpcMaxBodyBytes: JSON-RPC body inspection limit - Mcp: MCP-specific policy options (new McpOptions type) L7Allow and L7DenyRule field 9: - Params: MCP params matcher map for tools/call filtering New type McpOptions with StrictToolNames and AllowAllKnownMcpMethods optional booleans matching the proto definitions. Signed-off-by: Roland Huss <rhuss@redhat.com>
Change coverage_test.go from t.Logf (silent) to t.Errorf so that unhandled proto fields fail the test immediately. Add coverage tests for NetworkEndpoint (23 fields), L7Allow (8 fields), L7DenyRule (8 fields), and McpOptions (2 fields). Any new proto field that is not in the handled set or explicitly skipped now breaks the build, closing the silent-drift gap. Signed-off-by: Roland Huss <rhuss@redhat.com>
|
Addressed all 5 blockers from the latest review: 1. + 2. TLS.Insecure = skip cert verify (58f30d1): 3. Missing policy proto fields (6686187): Added all 6 fields: 4. Coverage test enforcement (12daaba): Changed 5. CI workflow (b0d375f): Added Test count: 151 (was 147). All pass with |
Add a Go SDK job to branch-checks.yml that runs mise run go:ci (lint, build, test, proto-check, docs-check) on every PR. This ensures the SDK is tested in CI, not just locally. Signed-off-by: Roland Huss <rhuss@redhat.com>
b0d375f to
5f33631
Compare
#6 Fix broken godoc examples: add workspace parameter to all method calls in doc.go that were broken after workspace scoping. #7 Add Err field to Event[T]: Watch error events now carry the underlying error instead of discarding it. #8 Separate Unauthenticated from PermissionDenied: add ErrorUnauthenticated code and IsUnauthenticated() helper. gRPC Unauthenticated (401) now maps to its own code instead of collapsing into PermissionDenied (403). #9 Add Unwrap to StatusError: replace dead Details field with Cause error field. StatusError.Unwrap() returns Cause, enabling errors.Is/As unwrapping. FromGRPCError and contextError both populate Cause. Signed-off-by: Roland Huss <rhuss@redhat.com>
|
Re-reviewed at Blockers — all confirmed fixed#1 + #2 TLS/auth (58f30d1) — Fixed, and confirmed at the wire level rather than just checking the error changed. All six auth/transport combinations now construct a client. Against a real gRPC server presenting a self-signed cert with a deliberately wrong CN: That proves both halves: #3 Policy fields (6686187) — Fixed. #4 Coverage enforcement (12daaba) — Fixed. #5 CI (b0d375f) — Fixed and correctly gated. Traced Full suite passes with Two new itemsGo formatting is unchecked, and the fix commit is already unformatted.
Findings 6–9 unchangedConsistent with your comment, which only claimed the blockers. Restating for triage, since these are API-surface decisions that get harder to change after release:
Of these I'd push for #8 and #9 in this PR: adding SummaryThe blocker work is solid and independently verified. I'd ask for the |
|
Addressed all should-fix items (#6-#9) in 58374d8:
Re: 151 tests, all pass with |
|
Checked at #6–#9 confirmed fixed#6 godoc examples — Fixed, and I verified more than the claim. Rather than just checking the #7 #8 Unauthenticated — Verified both directions, no leakage: Also a good call appending the new code at the end of the #9
151 tests, pass with Still outstanding: gofmtThe
This doesn't carry the risks cited for the deferral: gofmt isn't a security linter, can't flag Two lines closes it: ["go:format:check"]
dir = "sdk/go"
run = "gofmt -l . | tee /dev/stderr | (! read)"...added to Also unaddressed, both minor and fine to carry to Drop F: SummaryEverything substantive is done and independently verified — the blockers and all four should-fix items. The only thing I'd still ask for before merge is |
|
Added Note: the should-fix items #6-#9 were already addressed in 58374d8 (pushed before the re-review at b0d375f). That commit adds |
|
The The coverage guard still fires after the reformat: removing 151 tests pass with Where the PR standsEverything raised across the review rounds is now resolved and independently verified:
Two minor items remain deliberately deferred to Drop F, both fine to carry: Thanks for the quick turnaround on all of these, and for splitting the contribution into reviewable drops — it made this tractable. No further review comments from me. This looks ready to merge once CI is green. |
|
/ok to test 2515210 |
2515210 to
02717b8
Compare
|
/ok to test 02717b8 |
| url = "https://storage.googleapis.com/skaffold/releases/v2.20.0/skaffold-linux-arm64" | ||
|
|
||
| [tools.skaffold."platforms.linux-x64"] | ||
| checksum = "blake3:4de6b14984ff1c7e5f107dd12d15890feb4b6600032d61158162c243a81d9156" |
02717b8 to
14aec8d
Compare
Add gofmt format verification to go:ci. Catches unformatted Go files before they reach the PR. Fix formatting on coverage_test.go. Signed-off-by: Roland Huss <rhuss@redhat.com>
14aec8d to
5ed39ca
Compare
|
/ok to test 5ed39ca |
Context
This is the first PR in a 6-PR decomposition of the Go SDK contribution (#2044). The decomposition was discussed in the contributor meeting on 2026-07-14 to make the review process more approachable.
The first PR is intentionally the largest because it carries the shared foundation. After this merge, the SDK is usable end-to-end for sandbox management. Each subsequent PR then incrementally adds one more resource group, and after every merge the SDK is fully working with an expanded API surface.
What's in this PR
go.mod,go.sum,Makefile,mise.tomltypes/package (14 files) covering every SDK resourceClientInterface: all 10 sub-client accessors defined upfrontUnimplementederrors linking to feat(sdk/go): Go SDK PR decomposition plan #2270. Each subsequent PR replaces stubs with real implementations.How to Review
Review zones
client.go,types/*.go,errors.go,auth*.go,sandbox.go,sandbox_client.go,internal/grpc/conn.gosandbox_client_test.go,internal/converter/sandbox.go,internal/converter/sandbox_test.gosandbox_client_test.goas the test pattern exemplar. Converter tests follow table-driven patterns.stub_clients.go,go.sum,Makefile,mise.toml,doc.go, interface-only files (exec.go,file.go, etc.)proto/*.pb.go,proto/*_grpc.pb.goKey design decisions
types/package has no proto imports, insulating consumers from wire format changesErrorUnimplementedwith a link to the tracking issue. Each follow-up PR replaces stubs with real implementations without modifyingclient.go.What to look for
ClientInterfacecovers the right API surfaceIsNotFound(), etc.)Testing
All 130 tests pass:
Resolves #2044 (with remaining PRs B-F)
Part of #2270