projectapi

package
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Sep 11, 2026 License: AGPL-3.0 Imports: 13 Imported by: 0

Documentation

Overview

Package projectapi is how Patch reads and writes one project's resources — always as the person who asked, never as itself.

The service holds no credential for a customer's project. It has a service-account identity for asking the platform who a caller is and whether they may act on a project (see internal/auth), and that identity is deliberately good for nothing else. So every request this package makes carries the caller's own bearer token, taken from the authenticated request, and the project comes from the request the platform already authorized. A Client has no token field at all: there is nothing here to fall back to when a caller has none, which is what makes "act as the caller" a property of the type rather than a rule someone has to remember.

The wire format is plain JSON over the project's own API prefix, decoded into map[string]any rather than typed structs. That is not laziness: the whole point of the base tools is to work with any kind a project serves, including kinds this repository has never heard of, so a typed client would be a list of the kinds we happened to compile in.

Index

Constants

View Source
const (
	// DefaultTimeout bounds one request. These run inside a chat turn, so a
	// slow answer is worse than a fast failure the model can report.
	DefaultTimeout = 20 * time.Second
)

Variables

View Source
var ErrKindNotServed = errors.New("this project does not offer that kind of resource")

ErrKindNotServed reports that the project does not serve a kind at all — distinct from serving it and holding none of it.

The two call for opposite actions and must never arrive as the same answer: an empty list means there is nothing there yet, and a kind nobody is serving means nothing looked. Matched with errors.Is.

Functions

func ConditionTrue

func ConditionTrue(obj Object, conditionType string) bool

ConditionTrue reports whether the object's status carries condition type with status "True".

func IsForbidden

func IsForbidden(err error) bool

IsForbidden reports whether err is a "you may not" rejection.

func IsNotFound

func IsNotFound(err error) bool

IsNotFound reports whether err is a "no such object" rejection.

func Nested

func Nested(obj Object, path ...string) (any, bool)

Nested walks path through nested objects and returns what it finds.

func NestedInt64

func NestedInt64(obj Object, path ...string) (int64, bool)

NestedInt64 reads a number at a path. JSON numbers decode as float64, which is what makes this worth a helper rather than a type assertion at each site.

func NestedMap

func NestedMap(obj Object, path ...string) (map[string]any, bool)

NestedMap reads a nested object at a path.

func NestedSlice

func NestedSlice(obj Object, path ...string) ([]any, bool)

NestedSlice reads a nested array at a path.

func NestedString

func NestedString(obj Object, path ...string) (string, bool)

NestedString reads a string at a path, reporting whether one was there.

Types

type APIError

type APIError struct {
	// Code is the HTTP status.
	Code int
	// Status is the platform's own reply, when it sent a structured one.
	Status *metav1.Status
	// Body is the raw reply, for the case where it did not.
	Body string
}

APIError is a rejection from the platform, kept whole. The status carries the field paths a rejection names, which are the part a person acts on.

func (*APIError) Error

func (e *APIError) Error() string

func (*APIError) FieldErrors

func (e *APIError) FieldErrors() []FieldError

FieldErrors returns the field/message pairs a rejection named, plus the platform's own summary. The summary is included on purpose: it is the wording a person quotes when they escalate.

func (*APIError) IsForbidden

func (e *APIError) IsForbidden() bool

IsForbidden reports whether the caller may not do this.

func (*APIError) IsNotFound

func (e *APIError) IsNotFound() bool

IsNotFound reports whether the object asked for is not there.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client reaches the platform API. It is safe for concurrent use and holds no credential: see Client.As.

func New

func New(cfg Config) (*Client, error)

New builds a Client. It fails only on a configuration that could never work — no base URL, or a CA bundle that is not PEM — so a deployment mistake surfaces at boot rather than as an unexplained failure mid-conversation.

func (*Client) As

func (c *Client) As(project, bearerToken string) *Project

As returns a view of one project that acts as the holder of bearerToken.

Both arguments come from the authenticated, authorized request and from nowhere else. A Project built with an empty token can still be used, and every call it makes is refused by the platform — which is the correct outcome, and a far better one than quietly reading as the service.

type Config

type Config struct {
	// BaseURL is the platform API this project's resources are served from.
	BaseURL string
	// CACert verifies the server. Empty uses the system roots.
	CACert []byte
	// Timeout overrides [DefaultTimeout] when > 0.
	Timeout time.Duration
	// Transport is the test seam. Nil builds one from CACert.
	Transport http.RoundTripper
}

Config builds a Client.

type FieldError

type FieldError struct {
	// Field is the path the platform named, e.g. "spec.replicas". Empty when
	// the rejection is about the request as a whole.
	Field string `json:"field,omitempty"`
	// Message is the platform's own wording, kept verbatim so it can be quoted.
	Message string `json:"message"`
}

FieldError is one rejection and the field it names.

type Object

type Object = map[string]any

Object is one resource, as it travels on the wire.

type Project

type Project struct {
	// contains filtered or unexported fields
}

Project reads and writes one project's resources as one caller.

func (*Project) Create

func (p *Project) Create(ctx context.Context, r Resource, obj Object, dryRun bool) (Object, error)

Create creates the object, or — with dryRun — asks the platform whether it would accept one without keeping anything.

func (*Project) Get

func (p *Project) Get(ctx context.Context, r Resource, namespace, name string) (Object, error)

Get returns one object. A missing one comes back as an *APIError that IsNotFound recognizes, so callers can tell "not there" from "went wrong".

func (*Project) List

func (p *Project) List(ctx context.Context, r Resource, namespace string) ([]Object, error)

List returns every object of the kind. An empty namespace reads across all of them, which is also the only correct call for a kind held in none.

func (*Project) Name

func (p *Project) Name() string

Name is the project every request this view makes is scoped to.

func (*Project) OpenAPI

func (p *Project) OpenAPI(ctx context.Context, group, version string) (map[string]any, error)

OpenAPI returns the schema document describing one group and version.

func (*Project) Resolve

func (p *Project) Resolve(ctx context.Context, group, version, kindOrResource string) (Resource, error)

Resolve maps a group, version and a kind (or a plural resource name) onto the resource the project actually serves, and reports whether it is held in a namespace.

Both spellings are accepted because both turn up: a person says "Workload" and a manifest says "workloads", and asking a model to know which one this tool wants is a needless way to fail.

func (*Project) Update

func (p *Project) Update(ctx context.Context, r Resource, obj Object, dryRun bool) (Object, error)

Update replaces the object, or — with dryRun — asks whether the replacement would be accepted. The object carries the version it was read at, so a change somebody else made in between is refused by the platform rather than overwritten.

type Resource

type Resource struct {
	Group      string
	Version    string
	Resource   string
	Kind       string
	Namespaced bool
}

Resource identifies one kind as the project serves it.

func (Resource) GroupVersion

func (r Resource) GroupVersion() string

GroupVersion renders "group/version", or just "version" for the core group.

Jump to

Keyboard shortcuts

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