devedge-sdk

module
v0.64.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 11, 2026 License: Apache-2.0

README ΒΆ

devedge-sdk

CI Docs Go Reference

A complete, secure-by-default microservice from a single proto. Define a resource and its methods in proto; devedge-sdk gives you a running gRPC + REST service with Google-AIP semantics, fail-closed authorization, multi-tenant isolation, and a persistence/eventing layer wired in β€” every backend a swappable seam, every security invariant provable in CI.

It is the runtime companion to devedge: devedge is the dev- and deploy-time edge; devedge-sdk is the runtime library that production services import.

Status: early. APIs will change. Pin a version and read the changelog/releases before upgrading. The operational baseline is still filling in β€” built-in observability and health/readiness probes are tracked on the foundation roadmap (#97).

πŸ“š Documentation

Full docs live at infobloxopen.github.io/devedge-sdk. Start here:

Section What's there
πŸš€ Getting Started Install the SDK and stand up a running, fail-closed service in five minutes (Quickstart).
πŸ’‘ Concepts The architecture and seam model, the annotation contract, tenant isolation, aggregates, and events.
πŸ“– Guides Task how-tos: define a service, model a resource, pick a storage shape, run seccheck.
πŸ“‘ Reference Per-package API reference and codegen-plugin docs.
πŸŽ“ Tutorial Build the API Key Manager service end to end.

Why devedge-sdk

  • From one proto to a running, AIP-correct service. Scaffold a service, declare your resource and methods, and server.New stands up gRPC plus an optional HTTP/JSON gateway with the standard methods and Google-AIP semantics already wired: field-mask PATCH (AIP-134), ETag/If-Matchβ†’412 optimistic concurrency (AIP-154), pagination, filtering (AIP-160), soft-delete + undelete (AIP-148/149), batch methods (AIP-137), request de-duplication (AIP-155), and long-running operations (AIP-151/152). Correct API semantics, for free.
  • Secure by default β€” and provable. Authorization is fail-closed: annotate each RPC with (infoblox.authz.v1.rule) and the service refuses to boot if any served method is undeclared. Every query is scoped by account-id at the storage layer (GORM and ent), so one principal can never see another's resources; secret-annotated fields are encrypted at rest and never returned; and errors never leak SQL or stack traces. The seccheck package proves all of it in CI.
  • Pluggable seams, dev defaults, zero service-code change. Persistence (in-memory β†’ GORM/ent), transactions, domain events (in-memory β†’ Kafka, via a transactional outbox), the authz decision point, and the secret encryptor each ship a dev-suitable default and swap for a production backend without touching service code. DDD aggregates and multi-surface projections are first-class.
  • Codegen from your proto; dependency-light core. protoc-gen-svc scaffolds the service, protoc-gen-storage emits a GORM repository, protoc-gen-ent emits an ent schema, and protoc-gen-devedge-authz emits the authz-rules table β€” the proto is the single source of truth. Core packages depend only on the standard library: no ORM, no policy-engine dependency.

Install

go get github.com/infobloxopen/devedge-sdk@latest

Install the codegen plugins onto your PATH so buf generate can invoke them:

go install github.com/infobloxopen/devedge-sdk/cmd/protoc-gen-svc@latest
go install github.com/infobloxopen/devedge-sdk/cmd/protoc-gen-storage@latest
go install github.com/infobloxopen/devedge-sdk/cmd/protoc-gen-ent@latest
go install github.com/infobloxopen/devedge-sdk/cmd/protoc-gen-devedge-authz@latest

Requires Go 1.25+ and buf. Postgres and Vault are only needed for the production storage and secret backends β€” the in-memory store and dev encryptor run in-process. Full prerequisites: Installation.

Quickstart

In about five minutes you go from a .proto to a running, fail-closed gRPC + REST service.

1. Declare each RPC's authz requirement in proto β€” verb + resource is all a method needs:

service WidgetService {
  rpc GetWidget(GetWidgetRequest) returns (Widget) {
    option (infoblox.authz.v1.rule) = {verb: "get", resource: "widget:{id}"};
  }
  rpc CreateWidget(CreateWidgetRequest) returns (Widget) {
    option (infoblox.authz.v1.rule) = {verb: "create", resource: "widget"};
  }
}

2. Generate (buf generate) β€” protoc-gen-devedge-authz emits a WidgetServiceAuthzRules table next to the .pb.go.

3. Wire the server. The Authorizer defaults to default-deny, so every call is denied until you grant something β€” fail-closed by construction:

srv, err := server.New(server.Config{
    GRPCAddr: ":9090",
    HTTPAddr: ":8080", // optional HTTP/JSON gateway; omit to run gRPC-only
    Rules:    widgetv1.WidgetServiceAuthzRules, // generated in step 2

    // Dev decision point β€” grant group:admin everything. Swap for an
    // OPA/Cedar/remote Authorizer in production; nothing else changes.
    Authorizer: authz.NewDevAuthorizer(authz.Grant{
        Tenant: "t1", Subjects: []string{"group:admin"},
        Verbs: []authz.Verb{"*"}, Resource: "*",
    }),
    // Derive the principal from request metadata (account-id β†’ tenant, groups β†’
    // group:<name>). Use a verified-token func in production.
    PrincipalFunc: grpcauthz.DevPrincipalFunc(),
})
if err != nil {
    log.Fatal(err)
}

widgetv1.RegisterWidgetServiceServer(srv.GRPCServer(), &widgetServer{})
log.Fatal(srv.Serve(ctx)) // blocks until ctx is cancelled

You now have a running, fail-closed service speaking gRPC and REST. The chain server.New builds, outermost first:

RequestID β†’ ErrorMapper β†’ TenantID β†’ grpcauthz (fail-closed) β†’ FieldMask β†’ ETag/412 β†’ ReadMask β†’ ValidateOnly β†’ Deduplicate

β†’ Full walkthrough with tests: Quickstart.

Packages

Package What it provides
server Server lifecycle: gRPC + optional HTTP/JSON gateway, the interceptor chain auto-wired, graceful shutdown.
middleware The interceptors: RequestID, TenantID, FieldMask, ErrorMapper, ValidateOnly, Dedup, and etag.
authz Engine-neutral model: Principal, Resource, Verb, AccessRequest, Decision, the pluggable Authorizer, and DevAuthorizer (in-process, default-deny).
authz/grpcauthz Fail-closed gRPC interceptor + boot gate. Rough-compatible with atlas-authz-middleware/grpc_opa (COMPAT.md).
authz/catalog Builds the permission catalog (per resource: verbs, endpoints, View/Manage groups) from declared rules.
authz/authzpb Reflection-based rule extractor β€” reads (infoblox.authz.v1.rule) off linked descriptors, no generated file.
persistence ORM-free Repository[T,K] seam, in-memory dev store, transactions, batch, DSN hotload, filtering, and aggregate roots. Storage shape is per-service (SHAPES.md).
events Domain events via a transactional outbox β€” Publisher/Bus/idempotency, an in-memory bus, and a Kafka bus, for safe cross-aggregate reactions.
secret Secret-at-rest Encryptor: AES-256-GCM + HMAC for dev, HashiCorp Vault Transit for prod.
lro AIP-151/152 long-running operations: Store, Manager, Operation, cancellation.
cells Cell-based routing (isolation, not load balancing): a tenant→cell RoutingTable + watch-fed Router with a fail-safe default cell, an epoch-fenced GateRegistry admission barrier, and gRPC/HTTP middleware that rejects calls for a tenant mid-move.
seccheck Static + dynamic security assertions you run in CI (see Security model).

Full API reference for every package: Reference docs β†—.

Codegen plugins

The proto is the single source of truth; make generate (or buf generate) drives these:

Plugin (cmd/…) Output
protoc-gen-svc service scaffold (*.svc.go)
protoc-gen-storage GORM-backed Repository (*.storage.go)
protoc-gen-ent ent schema (ent/schema/*.go)
protoc-gen-devedge-authz the <Service>AuthzRules []MethodRule table (*.authz.go)

Security model

Security is a foundation property here, not a bolt-on: it is enforced by construction and verified in CI, so a correctly-built service is secure by default.

Authorization is fail-closed: an undeclared or ungranted method is denied with no code required. The seccheck package turns the model's invariants into assertions you run in CI (make security-check):

Invariant Asserted by
Every RPC has (infoblox.authz.v1.rule) or public: true AssertRulesComplete
No secret-annotated field value in a read/list response AssertNoSecretFieldsLeaked
Unknown principal β†’ PermissionDenied on all RPCs AssertUnknownPrincipalDenied
Account A cannot read Account B's resources AssertCrossAccountIsolation
Errors never leak SQL, stack traces, or hostnames AssertErrorMessagesClean

β†’ Security Check guide.

Secret fields. Mark a field secret in proto; generated code hashes it for lookup and encrypts the ciphertext β€” AES-256-GCM in dev, HashiCorp Vault Transit in production β€” so plaintext is never persisted and never returned. See model a resource β†’ secret fields and the Vault Transit guide.

Swapping the decision point

WithAuthorizer / Config.Authorizer takes any authz.Authorizer. To target a production engine, implement the one-method interface β€” an OPA-backed authorizer calling a sidecar, a Cedar/OpenFGA client, a remote PDP β€” and pass it in. Nothing else in the service changes. The SDK core stays engine-neutral: no OPA, no ORM, no policy-model types β€” those belong in adapters built on the SDK.

Building from source

This repo is a multi-module workspace (WS-011 / F039): the dep-light root library plus six nested modules (cmd, config/koanf, events/kafkabus, observability/otel, persistence/gormtx, persistence/entrepo). A committed go.work resolves the cross-module references locally; the build/vet/test targets loop over every module (the MODULES list in the Makefile).

make build                 # build every module (via go.work)
make test                  # unit tests across every module
make vet                   # go vet across every module
make lint                  # golangci-lint if installed, else go vet
make build-gowork-off      # build each module with the workspace OFF (real requires only)
make check-graph-isolation # prove a server-only consumer's graph is free of the heavy adapter deps
make generate              # rebuild plugins + regenerate after any .proto change
make security-check        # run the seccheck assertions
make release VERSION=vX.Y.Z   # synchronized multi-module release (dry run; PUSH=1 to publish)

testdata/toy, testdata/apikey, testdata/fleet, and testdata/iam are separate consumer modules with their own integration tests, deliberately NOT in go.work β€” run them with cd testdata/<name> && GOWORK=off go test ./.... To carve a future heavy component into its own isolated module, follow the Adding an Isolated Module checklist. See AGENTS.md for the full contributor guide.

License

Apache-2.0. See LICENSE.

Directories ΒΆ

Path Synopsis
Package apilayout is the URL layout strategy seam: it turns a resource's (domain, version, resource) coordinates into a REST path according to a chosen, named strategy.
Package apilayout is the URL layout strategy seam: it turns a resource's (domain, version, resource) coordinates into a REST path according to a chosen, named strategy.
Package authn defines the transport-neutral, pluggable AUTHENTICATION seams for devedge services β€” the "verify" and "mint" halves of the two-tier token model (WS-026).
Package authn defines the transport-neutral, pluggable AUTHENTICATION seams for devedge services β€” the "verify" and "mint" halves of the two-tier token model (WS-026).
oidc module
Package authz defines a clean, transport-neutral, pluggable authorization model for Infoblox services.
Package authz defines a clean, transport-neutral, pluggable authorization model for Infoblox services.
authzpb
Package authzpb extracts declared authorization rules from compiled protobuf descriptors.
Package authzpb extracts declared authorization rules from compiled protobuf descriptors.
catalog
Package catalog turns declared method rules into the permission catalog β€” the code-backed source of truth that the API enforces, that a portal can render as a role-creation UI, and that a downstream engine/policy generator can consume.
Package catalog turns declared method rules into the permission catalog β€” the code-backed source of truth that the API enforces, that a portal can render as a role-creation UI, and that a downstream engine/policy generator can consume.
devsvc
Package devsvc is the out-of-process, hot-reloadable sibling of the in-process authz.DevAuthorizer (WS-026 P1b): the dev-manipulable OSS reference behind the authz.Authorizer seam.
Package devsvc is the out-of-process, hot-reloadable sibling of the in-process authz.DevAuthorizer (WS-026 P1b): the dev-manipulable OSS reference behind the authz.Authorizer seam.
grpcauthz
Package grpcauthz wires the SDK's pluggable authz.Authorizer into gRPC as a fail-closed server interceptor.
Package grpcauthz wires the SDK's pluggable authz.Authorizer into gRPC as a fail-closed server interceptor.
Package cells implements the synchronous routing plane for cell-based development: routing each tenant to an isolated cell with a fail-safe default, rejecting calls for a tenant that is moving, and enforcing the current route epoch cell-side.
Package cells implements the synchronous routing plane for cell-based development: routing each tenant to an isolated cell with a fail-safe default, rejecting calls for a tenant that is moving, and enforcing the current route epoch cell-side.
cmd module
Package config provides a stdlib-only, dependency-light configuration seam.
Package config provides a stdlib-only, dependency-light configuration seam.
koanf module
Package events is the F032 transactional-outbox + domain-events seam: a backend-neutral way to react to a change in one aggregate by changing another, WITHOUT making the two changes one transaction (which F031 forbids across aggregate boundaries) and WITHOUT a dual write that loses the second step on a crash.
Package events is the F032 transactional-outbox + domain-events seam: a backend-neutral way to react to a change in one aggregate by changing another, WITHOUT making the two changes one transaction (which F031 forbids across aggregate boundaries) and WITHOUT a dual write that loses the second step on a crash.
membus
Package membus is the in-process, channel-based dev/embedded implementation of the events.Bus seam β€” Phase 1 of the SDK event-bus stack.
Package membus is the in-process, channel-based dev/embedded implementation of the events.Bus seam β€” Phase 1 of the SDK event-bus stack.
kafkabus module
Package featureflags is the local, in-process feature-flag evaluator (seam P3b) β€” the first consumer of the per-tenant rules substrate (rules, seam P3a).
Package featureflags is the local, in-process feature-flag evaluator (seam P3b) β€” the first consumer of the per-tenant rules substrate (rules, seam P3a).
Package health provides the readiness-check seam for devedge-sdk services.
Package health provides the readiness-check seam for devedge-sdk services.
internal
aip
Package aip is the shared, generator-agnostic resolver for the AIP contract facts devedge services declare in proto β€” field_behavior, AIP standard-method classification, and AIP-122 resource identity.
Package aip is the shared, generator-agnostic resolver for the AIP contract facts devedge services declare in proto β€” field_behavior, AIP standard-method classification, and AIP-122 resource identity.
Package lro implements the AIP-151 Long-Running Operation pattern.
Package lro implements the AIP-151 Long-Running Operation pattern.
idempotency.go β€” the DURABLE, exactly-once request-idempotency path (WS-043 / F048), the transactional upgrade of the best-effort in-memory DeduplicateUnary (F023).
idempotency.go β€” the DURABLE, exactly-once request-idempotency path (WS-043 / F048), the transactional upgrade of the best-effort in-memory DeduplicateUnary (F023).
etag
Package etag provides gRPC middleware for HTTP ETag / conditional-request semantics: it reads the If-Match precondition from incoming metadata and writes the ETag for the response to the outgoing trailer.
Package etag provides gRPC middleware for HTTP ETag / conditional-request semantics: it reads the If-Match precondition from incoming metadata and writes the ETag for the response to the outgoing trailer.
redact
Package redact provides proto-reflection-based helpers that replace write-only field values with "[REDACTED]" (strings) or the zero value (other kinds) before they are logged or returned.
Package redact provides proto-reflection-based helpers that replace write-only field values with "[REDACTED]" (strings) or the zero value (other kinds) before they are logged or returned.
observability
otel module
Package persistence provides connection and storage helpers for Infoblox services.
Package persistence provides connection and storage helpers for Infoblox services.
filter
Package filter implements an AIP-160 subset parser for list filter expressions and an AIP-132 parser for order_by strings.
Package filter implements an AIP-160 subset parser for list filter expressions and an AIP-132 parser for order_by strings.
resourcename
Package resourcename provides AIP-122 resource name formatting and parsing.
Package resourcename provides AIP-122 resource name formatting and parsing.
entrepo module
gormtx module
migrate module
proto
Package quota is the usage/quota metering seam (P13) β€” deliberately SEPARATE from the authz decision (P12).
Package quota is the usage/quota metering seam (P13) β€” deliberately SEPARATE from the authz decision (P12).
Package reference is the cross-service resource-reference seam (F041, WS-021 P1).
Package reference is the cross-service resource-reference seam (F041, WS-021 P1).
Package resilience provides policy interceptors for request timeouts, rate limiting, and circuit-breaker seams.
Package resilience provides policy interceptors for request timeouts, rate limiting, and circuit-breaker seams.
Package rules is the per-tenant rules-distribution substrate (seam P3a): a pluggable Source that delivers a typed ruleset per tenant and streams changes, plus a fail-safe local Cache that keeps a last-known-good snapshot so consumers evaluate locally β€” never a per-operation call to a rules service.
Package rules is the per-tenant rules-distribution substrate (seam P3a): a pluggable Source that delivers a typed ruleset per tenant and streams changes, plus a fail-safe local Cache that keeps a last-known-good snapshot so consumers evaluate locally β€” never a per-operation call to a rules service.
Package server provides a batteries-included gRPC server builder for Infoblox services.
Package server provides a batteries-included gRPC server builder for Infoblox services.
idempotency.go β€” WS-043 / F048 Increment 2, Deliverable A: servicekit auto-wiring of the durable, exactly-once request-idempotency path plus a host-scheduled GC sweep.
idempotency.go β€” WS-043 / F048 Increment 2, Deliverable A: servicekit auto-wiring of the durable, exactly-once request-idempotency path plus a host-scheduled GC sweep.
Package servicekittest provides generated-quality contract harnesses for the WS-012 composable-services test pyramid (proposal Β§7).
Package servicekittest provides generated-quality contract harnesses for the WS-012 composable-services test pyramid (proposal Β§7).
Package slo is the reliability seam for devedge services (WS-025): an OpenSLO v1 intermediate representation, contract-derived default SLOs, a fail-loud three-layer classifier, and pure-text emitters that project the IR to Prometheus/Cortex rules, Grafana dashboards, and Loki LogQL rules.
Package slo is the reliability seam for devedge services (WS-025): an OpenSLO v1 intermediate representation, contract-derived default SLOs, a fail-loud three-layer classifier, and pure-text emitters that project the IR to Prometheus/Cortex rules, Grafana dashboards, and Loki LogQL rules.
Package tagging is the local, in-process tag-governance validator (seam P3b for a richer rule type) β€” a second consumer of the per-tenant rules substrate (rules, seam P3a), after feature flags.
Package tagging is the local, in-process tag-governance validator (seam P3b for a richer rule type) β€” a second consumer of the per-tenant rules substrate (rules, seam P3a), after feature flags.
Package types provides reusable, ORM-agnostic field types for Infoblox resources.
Package types provides reusable, ORM-agnostic field types for Infoblox resources.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL