Skip to content

infobloxopen/devedge-sdk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

314 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

devedge-sdk

CI Docs Go Reference Go 1.25+ License: Apache 2.0

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.

About

No description, website, or topics provided.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors