Help us shape the future of Go! Take the 2026 Go Developer Survey

flags

package
v1.1.1 Latest Latest
Warning

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

Go to latest
Published: Sep 18, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

README

Boolean feature evaluation

Evaluator owns the application contract for optional product behavior. Permissions, tenant isolation and subscription entitlements still apply when a flag evaluates to true. This package does not administer flags or deploy flagd.

The contract imports only the standard library and UUID values. Supply your own Evaluator, as in the executable example, or explicitly select the OpenFeature adapter or OFREP adapter. SDK dependencies belong to those packages. Scope.Valid checks that each targeting scope part is nonblank UTF-8; it preserves the identity supplied by the installation.

Compose ofrep.New with an application, installation and environment scope, an existing service URL, an explicit timeout and optional bearer token. TLS verifies the server against system roots or the supplied CA file. HTTP requires an explicitly configured loopback endpoint for local development. Construction validates configuration without a network request; the first evaluation checks reachability. Drain requests before calling Close, which releases the owned HTTP transport's idle connections and the isolated SDK instance.

Pass each module the Evaluator interface. Before an operation, call Boolean with the resolved tenant, a stable trusted subject identifier and an explicit fallback. Errors return that fallback with Defaulted: true; a configured false value is a successful decision. Missing flags, wrong types and provider outages have distinct errors. Provider diagnostic text does not escape the adapter.

The provider receives application, installation, environment, tenant_id and subject attributes. Its targeting key is the JSON array of those five values, preventing different tenants or installations sharing rollout buckets. These attributes are evaluation facts, not an authorization boundary: deployment must restrict access to the flag service. Use pseudonymous subject identifiers.

OFREP keys contain ASCII letters, digits, dots, underscores or hyphens; . and .. alone are refused. This prevents path traversal through the upstream URL join. Redirects are refused, and ambient proxy or FLAGD_* variables do not configure this adapter. Targeting and evaluation belong to the provider; there is no PlatformKit rule engine, cache or event stream.

Flagd supports OFREP on port 8016 by default and currently labels that service experimental. An installation must configure and verify its endpoint separately. openfeature.New also accepts other fresh providers at the composition boundary. Those providers must honor evaluation contexts; arbitrary blocking provider code cannot be preempted.

Migrate constructor imports

The SDK-backed constructors have moved out of this contract package. Update application composition when adopting this release; interface consumers retain the same flags types and error identities.

Previous API New API
flags.NewOpenFeature openfeature.New from kit/flags/providers/openfeature
*flags.OpenFeature *openfeature.Evaluator from that adapter
flags.NewOFREP ofrep.New from kit/flags/providers/ofrep
flags.OFREPConfig ofrep.Config from that adapter

Both constructors still return an evaluator with Boolean and Close; OFREP uses the same OpenFeature adapter for evaluation and lifecycle. Constructor signatures otherwise retain their arguments. Root-package forwarding functions are intentionally absent: importing a provider back into its contract would create a cycle and require SDKs for every custom evaluator. Existing installations need no schema or flag-definition migration for this source API change.

Run go test -race ./kit/flags/... for scope separation, concurrent evaluation, fallback, cancellation, lifecycle, TLS wire requests and configuration refusal. These use local fixtures; deployed service readiness, administration UI and downstream application adoption require separate verification.

Run go list -deps -f '{{if not .Standard}}{{.ImportPath}}{{end}}' ./kit/flags to check contract independence: only kit/flags and github.com/google/uuid should appear. No provider is activated merely by importing the contract.

Documentation

Overview

Package flags evaluates optional product behavior. Flags never grant permissions, change tenant isolation, or replace subscription entitlements.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalid      = errors.New("flags: invalid evaluation or configuration")
	ErrUnavailable  = errors.New("flags: provider unavailable")
	ErrNotFound     = errors.New("flags: flag not found")
	ErrTypeMismatch = errors.New("flags: flag is not boolean")
	ErrClosed       = errors.New("flags: evaluator closed")
)

Functions

This section is empty.

Types

type Decision

type Decision struct {
	Value     bool
	Variant   string
	Defaulted bool // the caller's fallback was used because evaluation failed
}

type Evaluator

type Evaluator interface {
	Boolean(context.Context, string, Subject, bool) (Decision, error)
}

Evaluator returns the explicit fallback with Defaulted set on every error. Evaluate once before an operation, using facts loaded by its trusted owner.

Example
package main

import (
	"context"
	"fmt"

	"github.com/google/uuid"
	"github.com/septagon-oss/platformkit/kit/flags"
)

// A product can supply immutable definitions without importing any SDK.
type definitions map[string]bool

func (d definitions) Boolean(ctx context.Context, key string, _ flags.Subject, fallback bool) (flags.Decision, error) {
	failed := flags.Decision{Value: fallback, Defaulted: true}
	if err := ctx.Err(); err != nil {
		return failed, err
	}
	value, ok := d[key]
	if !ok {
		return failed, flags.ErrNotFound
	}
	return flags.Decision{Value: value}, nil
}

func main() {
	var evaluator flags.Evaluator = definitions{"preview": false}
	subject := flags.Subject{TenantID: uuid.MustParse("bce3e021-5053-4c36-b4bd-c0a03c6f77b7"), TargetingKey: "member-1"}
	decision, err := evaluator.Boolean(context.Background(), "preview", subject, true)
	fmt.Println(decision.Value, decision.Defaulted, err)
	decision, err = evaluator.Boolean(context.Background(), "missing", subject, true)
	fmt.Println(decision.Value, decision.Defaulted, err)
}
Output:
false false <nil>
true true flags: flag not found

type Scope

type Scope struct {
	Application  string
	Installation string
	Environment  string
}

Scope is fixed at composition, never selected from request input.

func (Scope) Valid

func (s Scope) Valid() bool

Valid reports whether every scope part contains non-whitespace, valid UTF-8 text. Providers preserve these values when building targeting identities.

type Subject

type Subject struct {
	TenantID     uuid.UUID
	TargetingKey string
}

Subject belongs to the resolved tenant. TargetingKey is a stable, preferably pseudonymous account or actor identifier supplied by the application.

Directories

Path Synopsis
providers
ofrep
Package ofrep connects flags to an explicitly configured OFREP endpoint.
Package ofrep connects flags to an explicitly configured OFREP endpoint.
openfeature
Package openfeature adapts a selected OpenFeature SDK provider to flags.
Package openfeature adapts a selected OpenFeature SDK provider to flags.

Jump to

Keyboard shortcuts

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