schemas

package
v1.0.3 Latest Latest
Warning

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

Go to latest
Published: Jul 29, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package schemas talks to the public tabstack-schemas repository on GitHub and manages a local store of pulled schemas. It is deliberately separate from internal/client: that client is bound to the authenticated Tabstack API, whereas this fetches unauthenticated raw files from GitHub over a different host. Keeping them apart avoids leaking the API bearer token to GitHub and keeps each transport's concerns isolated.

Index

Constants

View Source
const DefaultRawBase = "https://raw.githubusercontent.com/Mozilla-Ocho/tabstack-schemas/main"

DefaultRawBase is the raw.githubusercontent.com root for the schema repo's main branch. Every schema and the index hang off this.

View Source
const IndexCacheName = ".index-cache.json"

IndexCacheName is the per-store cache of the library manifest, used to avoid refetching index.json on every list/pull/status.

View Source
const ManifestName = ".manifest.json"

ManifestName is the bookkeeping file recording what was pulled and from which remote content, so `schema status` can tell local edits from upstream drift.

Variables

This section is empty.

Functions

func CanonicalSHA

func CanonicalSHA(data []byte) string

CanonicalSHA returns the hex SHA-256 of the canonical JSON form of data, so formatting-only differences do not change the hash. Non-JSON input is hashed as raw bytes.

func Equal

func Equal(a, b []byte) bool

Equal reports whether two schema documents are semantically equal, ignoring formatting differences (whitespace, key order). This keeps a re-pull from flagging a conflict when only the on-disk formatting differs from the remote. If either side is not valid JSON we fall back to a raw byte comparison.

func FindLocal

func FindLocal(dir, selector string) (string, error)

FindLocal resolves a selector to a stored schema's repo-relative path by scanning dir. It is the offline counterpart to Index.Resolve: it works against already-pulled files without touching the network. A selector may be a repo-relative path (trailing .json optional) or a bare schema name; a bare name that matches more than one stored file returns an ambiguity error.

func ListLocal

func ListLocal(dir string) ([]string, error)

ListLocal returns the repo-relative paths of every schema stored under dir, sorted. Internal files (manifest, index cache) are skipped, and a missing store directory yields an empty list rather than an error.

func LocalPath

func LocalPath(dir, schemaPath string) string

LocalPath joins a storage directory with a repo-relative schema path. The repo layout (category/name.json) is mirrored on disk so a pulled schema keeps a stable identity for later comparison. It does not guard against traversal; callers that touch the filesystem with caller- or remote-supplied paths use SafePath instead.

func Read

func Read(dir, schemaPath string) ([]byte, bool, error)

Read returns the bytes of a locally stored schema. The bool reports whether the file exists; a missing file is not an error.

func SafePath

func SafePath(dir, schemaPath string) (string, error)

SafePath is LocalPath plus a containment check: it rejects any schema path that would escape dir. Both user selectors and remote index.json entries flow through here before any read/write, so a hostile manifest cannot read or clobber files outside the store.

Two layers: a lexical check rejects absolute paths and ".." traversal, then a symlink-resolved check rejects paths that escape via a symlinked component inside the store (e.g. <store>/jobs -> /etc, where jobs/x.json is lexically contained but writes to /etc/x.json). The returned path is the original lexical join (not the resolved one) so the on-disk layout stays stable.

func Write

func Write(dir, schemaPath string, data []byte) error

Write stores a schema under dir, creating parent directories as needed. Schemas are not secrets, so we use ordinary 0644/0755 permissions (unlike the 0600 config file).

Types

type Entry

type Entry struct {
	Category    string `json:"category"`
	Title       string `json:"title"`
	Description string `json:"description"`
	Path        string `json:"path"`
}

Entry is one schema's manifest record from index.json.

type FetchError

type FetchError struct {
	URL        string
	StatusCode int
}

FetchError is a non-2xx response from GitHub. We surface the URL and status so the command layer can produce a clear, actionable message.

func (*FetchError) Error

func (e *FetchError) Error() string

type Fetcher

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

Fetcher retrieves the index and individual schemas from the repo. The http.Client and base URL are injectable so tests can point at a mock, mirroring client.WithHTTPClient.

func NewFetcher

func NewFetcher(opts ...Option) *Fetcher

NewFetcher constructs a Fetcher pointed at the public schema repo.

func (*Fetcher) Fetch

func (f *Fetcher) Fetch(ctx context.Context, schemaPath string) ([]byte, error)

Fetch retrieves one schema by its repo-relative path (e.g. jobs/job-posting.json).

func (*Fetcher) Index

func (f *Fetcher) Index(ctx context.Context) (Index, error)

Index fetches and decodes index.json.

type Index

type Index struct {
	Name        string  `json:"name"`
	Description string  `json:"description"`
	Count       int     `json:"count"`
	Schemas     []Entry `json:"schemas"`
}

Index is the decoded index.json: a manifest of every available schema.

func CachedIndex

func CachedIndex(ctx context.Context, f *Fetcher, dir string, ttl time.Duration, refresh bool) (Index, error)

CachedIndex returns the library index, using a per-store cache file so we do not refetch index.json within ttl. refresh forces a fetch. If the network fetch fails but a (possibly stale) cache exists, the cache is returned so the commands keep working offline.

func (Index) Resolve

func (idx Index) Resolve(selector string) ([]Entry, error)

Resolve maps a user selector onto manifest entries. A selector may be:

  • a repo-relative path ("jobs/job-posting.json", trailing .json optional)
  • a category ("jobs") -> every schema in that category
  • a bare schema name ("job-posting") -> the matching schema

Bare names that match more than one schema, or that collide with a category, return an ambiguity error so the user can disambiguate with a full path.

type Manifest

type Manifest struct {
	Schemas map[string]ManifestEntry `json:"schemas"`
}

Manifest is the decoded .manifest.json, keyed by repo-relative schema path.

func LoadManifest

func LoadManifest(dir string) (Manifest, error)

LoadManifest reads the store manifest; a missing manifest yields an empty one.

func (Manifest) Remove

func (m Manifest) Remove(schemaPath string)

Remove drops the entry for a schema path.

func (Manifest) Save

func (m Manifest) Save(dir string) error

Save writes the manifest. json.MarshalIndent emits map keys in sorted order, so the file stays diff-friendly across pulls.

The write is atomic (temp file + rename) so a crash mid-write cannot leave a truncated, unparseable manifest behind. It is NOT locked, however: two concurrent `schema pull` runs against the same store still race, and the last writer wins, dropping the other's just-recorded entries (they then read as untracked until re-pulled). Running one pull at a time per store avoids this; a documented CLI limitation, not a guarantee.

func (Manifest) Set

func (m Manifest) Set(schemaPath, sha, pulledAt string)

Set records (or updates) the entry for a schema path.

type ManifestEntry

type ManifestEntry struct {
	SHA256   string `json:"sha256"`
	PulledAt string `json:"pulled_at"`
}

ManifestEntry records the canonical content hash of a schema as it was last pulled, plus when. Comparing this against the current local file detects local edits; comparing it against the current remote detects upstream changes.

type Option

type Option func(*Fetcher)

Option configures a Fetcher.

func WithHTTPClient

func WithHTTPClient(h *http.Client) Option

WithHTTPClient swaps the underlying http.Client. Mostly useful for tests.

func WithRawBase

func WithRawBase(base string) Option

WithRawBase overrides the raw content base URL. Mostly useful for tests.

Jump to

Keyboard shortcuts

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