Skip to content

Latest commit

 

History

History
73 lines (58 loc) · 3.68 KB

File metadata and controls

73 lines (58 loc) · 3.68 KB

Declared label targets: breaking migration

Treetop's early releases prioritize correctness and one explicit contract over backward compatibility. The 0.1.0 contract removes legacy behavior rather than retaining deprecated adapters. Upgrade the coordinated Core, Bundle, REST, SDK, CLI, frontend, and Bundle Action changes together.

Ownership and application

A labeler owns a tuple: (fully qualified Cedar resource type, attribute). App::Host and Other::Host are distinct types; a root-namespace Host is also an exact type. Entity IDs, namespace wildcards, and arbitrary Rust applicability predicates are not scopes.

Construct LabelTarget::new("App::Host", "labels") once, handle its validation error, and return the target from Labeler::target. Implement read-only derive logic. Use labeler.apply(&mut resource) for controlled direct application; it checks the resource type and leaves other types untouched.

The registry captures each declaration when built and rejects duplicate tuples before installation. It indexes validated Cedar types without reparsing them on requests. For a matching resource it clears all owned attributes before running any derivation, then applies labelers in registration order. A derivation returning None leaves its target absent. Equal attribute names on different types have independent owners. Reloads publish the complete immutable registry as part of one engine generation, and captured sessions retain their original generation.

Authorization impact

Only attributes owned on the actual resource type are server-derived labels. Other attributes remain trusted application inputs. Registering App::Host.labels does not remove or validate Other::Host.labels. Policies that rely on derived labels must constrain the resource type and install the corresponding owner. Review policies that previously relied on a global attribute-name reservation.

A labeler cannot echo its own incoming output. An earlier labeler cannot consume a forged value owned by a later labeler on the same type, because the registry clears every owned output first. Canonical id is reserved on all types.

Configuration

Bundle and REST label rules use an explicit target object:

{
  "target": { "resource_type": "App::Host", "attribute": "labels" },
  "field": "name",
  "patterns": [{ "name": "prod", "regex": "^prod" }]
}

Replace the old rule-level kind and output fields with target.resource_type and target.attribute. Old keys, unknown fields, missing target components, invalid Cedar resource types, empty attribute names, and reserved outputs are errors. Shared names on disjoint types require separate rules, not a dispatcher. Set bundle and module manifests to format_version = 2, then rebuild and re-sign bundles after migrating their configuration. Old archives and signatures are rejected.

Rust and wire consumers

  • Replace custom applies_to and output methods with target returning a validated LabelTarget. Create one labeler per exact target.
  • Pass the validated target to RegexLabeler::new(target, field, rules).
  • Replace UserPolicies with PolicyCandidates; replace its deprecated action aliases with candidate_actions and candidate_actions_by_name. Candidate listings do not evaluate Cedar conditions and never authorize operations.
  • Supply every policy-version field: hash, loaded_at, label_set, and generation. Use explicit null when no label-set identifier exists. Generation is an unsigned 64-bit value local to one engine instance. Omission is an error.

Old-server defaults, wildcard scopes, and deprecated label APIs are removed from the coordinated new contract. Candidate revisions are pinned for integration before publication.