pluginimport

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Oct 13, 2026 License: MPL-2.0 Imports: 31 Imported by: 0

Documentation

Overview

Package pluginimport mirrors plugin versions from upstream releases into an organization's plugin registry (ADR-0027 A1).

Index

Constants

View Source
const (
	BundleOutcomeImported = "imported"
	BundleOutcomeSkipped  = "skipped"
	BundleOutcomeMismatch = "mismatch"
	BundleOutcomeRefused  = "refused"
)

The outcomes of one bundled version (ADR-0029 D4, D5).

View Source
const (
	OutcomeImported        = "imported"
	OutcomeAlreadyMirrored = "already_mirrored"
	OutcomeRevoked         = "revoked"
	OutcomeRestored        = "restored"
	OutcomeFailed          = "failed"
)

Outcomes recorded per version and per platform of an import.

View Source
const (
	StateRunning            = "running"
	StateSucceeded          = "succeeded"
	StatePartiallySucceeded = "partially_succeeded"
	StateFailed             = "failed"
)

Job states, as the platform API reports them.

Variables

View Source
var ErrGitHubRateLimited = errors.New("GitHub rate limit reached")

ErrGitHubRateLimited is GitHub refusing an unauthenticated caller that has spent its hourly allowance (60 calls per egress address).

View Source
var ErrNotAReleaseLink = errors.New("not a release link of a packer-plugin repository")

ErrNotAReleaseLink is a link that names no packer-plugin release.

View Source
var ErrUpstreamNotFound = errors.New("not found upstream")

ErrUpstreamNotFound is an upstream answer that the product or version does not exist.

View Source
var ErrUpstreamUnavailable = errors.New("upstream unavailable")

ErrUpstreamUnavailable is an upstream that could not be reached or answered with a server error; it is distinct from an answer that something is absent.

View Source
var PruneAges = []int{1, 7, 14, 30, 60, 90, 180, 365}

PruneAges are the age limits the console offers, in days.

Functions

func HashiCorpKeyring

func HashiCorpKeyring() (openpgp.EntityList, error)

HashiCorpKeyring returns the pinned HashiCorp release-signing key.

func NewHTTPClient

func NewHTTPClient() *http.Client

NewHTTPClient is the client imports and catalogue reads share. It has no overall timeout, because a zip download may legitimately take minutes.

func NextPrune

func NextPrune(schedule string, now time.Time) (time.Time, error)

NextPrune is when a schedule next fires after now, in UTC.

func PruneOnce

func PruneOnce(ctx context.Context, prunes Pruning, emitter *audit.SystemEmitter, tenant store.OrganizationTenant, ageDays int, now time.Time) (int, error)

PruneOnce clears the organization's finished jobs older than ageDays and writes the audit pair for the run; the API's Prune now shares it.

func ValidProduct

func ValidProduct(product string) bool

ValidProduct reports whether product names a Packer plugin on releases.hashicorp.com.

func ValidPruneAge

func ValidPruneAge(days int) bool

ValidPruneAge reports whether days is one of the offered limits.

func ValidRepository

func ValidRepository(repository string) bool

ValidRepository reports whether repository is owner/packer-plugin-<name>.

Types

type BundleExports

type BundleExports interface {
	ClaimPluginBundle(context.Context, time.Duration) (*store.ClaimedPluginBundle, error)
	ExportablePluginVersions(context.Context, store.OrganizationTenant) ([]store.ExportablePlugin, error)
	OpenPluginObject(context.Context, string) (io.ReadCloser, error)
	PutPluginBundle(context.Context, store.OrganizationTenant, string, io.ReadSeeker, int64) error
	DeletePluginBundleObject(context.Context, store.OrganizationTenant, string) error
	RecordPluginBundle(context.Context, store.OrganizationTenant, *store.PluginBundleResult, string) error
}

BundleExports is where the exporter finds content and stores archives.

type BundleImporter

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

BundleImporter ingests uploaded plugin bundles.

func NewBundleImporter

func NewBundleImporter(imports BundleImports, keyring openpgp.EntityList, emitter *audit.SystemEmitter, interval time.Duration, logger *slog.Logger) *BundleImporter

NewBundleImporter polls queued bundle imports.

func (*BundleImporter) Run

func (b *BundleImporter) Run(ctx context.Context)

Run works queued imports until ctx ends.

func (*BundleImporter) RunOnce

func (b *BundleImporter) RunOnce(ctx context.Context) (bool, error)

RunOnce ingests at most one queued bundle.

type BundleImports

type BundleImports interface {
	ClaimPluginBundleImport(context.Context, time.Duration) (*store.ClaimedPluginBundleImport, error)
	RecordPluginBundleImport(context.Context, store.OrganizationTenant, string, store.PluginBundleOrigin, any, string) error
	OpenPluginObject(context.Context, string) (io.ReadCloser, error)
	DeletePluginBundleObject(context.Context, store.OrganizationTenant, string) error
	PluginVersionSumsDigest(context.Context, store.OrganizationTenant, string, string) (string, error)
	PublishPluginVersion(context.Context, store.OrganizationTenant, store.PluginVersionInput) error
}

BundleImports is where the importer finds uploaded bundles and publishes their versions.

type BundleVersionOutcome

type BundleVersionOutcome struct {
	Plugin           string `json:"plugin"`
	Version          string `json:"version"`
	OriginKind       string `json:"origin_kind"`
	OriginRepository string `json:"origin_repository,omitempty"`
	Outcome          string `json:"outcome"`
	Error            string `json:"error,omitempty"`
}

BundleVersionOutcome is one bundled version's result, with where the bundle said it came from.

type Catalogue

type Catalogue struct {
	*Upstream
	*GitHub
}

Catalogue is what the import screens read: HashiCorp's release service and GitHub releases.

type Checker

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

Checker asks each opted-in plugin's source for its newest stable release (ADR-0027 A6). It never imports.

func NewChecker

func NewChecker(checks UpdateChecks, upstream *Upstream, github *GitHub, interval time.Duration, logger *slog.Logger) *Checker

NewChecker checks each opted-in plugin once per interval.

func (*Checker) Run

func (c *Checker) Run(ctx context.Context)

Run checks due plugins until ctx ends, looking for more once a minute.

func (*Checker) RunOnce

func (c *Checker) RunOnce(ctx context.Context) (bool, error)

RunOnce checks at most one due plugin, reporting whether there was one.

type Exporter

type Exporter struct {
	DufflebagVersion string
	// contains filtered or unexported fields
}

Exporter builds queued plugin bundles.

func NewExporter

func NewExporter(exports BundleExports, emitter *audit.SystemEmitter, interval time.Duration, logger *slog.Logger) *Exporter

NewExporter polls queued bundle exports.

func (*Exporter) Run

func (e *Exporter) Run(ctx context.Context)

Run works queued exports until ctx ends.

func (*Exporter) RunOnce

func (e *Exporter) RunOnce(ctx context.Context) (bool, error)

RunOnce builds at most one queued bundle.

type GitHub

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

GitHub reads public releases from the GitHub API, unauthenticated (ADR-0027 A4).

func NewGitHub

func NewGitHub(client *http.Client, base string) *GitHub

NewGitHub reads releases from the API at base.

func (*GitHub) Release

func (g *GitHub) Release(ctx context.Context, repository, tag string) (GitHubRelease, error)

Release reads the release of repository at tag.

func (*GitHub) Resolve

func (g *GitHub) Resolve(ctx context.Context, link string) (GitHubRelease, error)

Resolve reads the release a link names. A /releases/latest link is resolved here, once, so an import fetches the exact tag it was shown.

type GitHubRelease

type GitHubRelease struct {
	Repository    string
	Name          string
	Tag           string
	Version       string
	Prerelease    bool
	PublishedAt   time.Time
	Platforms     []string
	HasChecksum   bool
	ChecksumAsset string
	// contains filtered or unexported fields
}

GitHubRelease is a release resolved to an exact tag.

type Importer

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

Importer mirrors versions from releases.hashicorp.com and GitHub releases.

func NewImporter

func NewImporter(upstream *Upstream, github *GitHub, keyring openpgp.EntityList, repository Repository) *Importer

NewImporter verifies every releases.hashicorp.com SHA256SUMS against keyring before storing it; GitHub releases carry no key to check.

func (*Importer) ImportGitHubVersion

func (i *Importer) ImportGitHubVersion(
	ctx context.Context, tenant store.OrganizationTenant, repository, tag string, platforms []string,
) VersionOutcome

ImportGitHubVersion mirrors one public GitHub release's selected platforms. Its signature, if any, is stored verbatim and never verified (ADR-0027 D11).

func (*Importer) ImportVersion

func (i *Importer) ImportVersion(
	ctx context.Context, tenant store.OrganizationTenant, product, version string, platforms []string,
) VersionOutcome

ImportVersion mirrors one releases.hashicorp.com version's selected platforms. It never returns an error: every failure is the version's recorded outcome.

func (*Importer) Sync

Sync applies one change a publisher made from a plugin's detail page (ADR-0027 A7): add platforms to a version or mirror a new one, or revoke or restore a version.

type Jobs

type Jobs interface {
	ClaimPluginImport(context.Context, time.Duration) (*store.ClaimedPluginImport, error)
	RecordPluginImport(context.Context, store.OrganizationTenant, uuid.UUID, string, any) error
}

Jobs is where the worker finds and records import jobs.

type PlatformOutcome

type PlatformOutcome struct {
	Platform string `json:"platform"`
	Outcome  string `json:"outcome"`
	Error    string `json:"error,omitempty"`
}

PlatformOutcome is one requested platform of one version.

type Pruner

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

Pruner clears finished jobs on each organization's schedule. One organization's run happens on one replica: the claim stamps it run.

func NewPruner

func NewPruner(prunes Prunes, emitter *audit.SystemEmitter, interval time.Duration, logger *slog.Logger) *Pruner

func (*Pruner) Run

func (p *Pruner) Run(ctx context.Context)

func (*Pruner) RunOnce

func (p *Pruner) RunOnce(ctx context.Context) (bool, error)

RunOnce prunes at most one organization, reporting whether one was due.

type Prunes

type Prunes interface {
	Pruning
	ClaimPluginPrune(ctx context.Context) (*store.ClaimedPluginPrune, error)
	RecordPluginPrune(ctx context.Context, tenant store.OrganizationTenant, cleared int, runErr string, nextAt *time.Time) error
}

Prunes is where the pruner finds due organizations and records runs.

type Pruning

type Pruning interface {
	PrunePluginImports(ctx context.Context, tenant store.OrganizationTenant, before time.Time) (int, error)
}

Pruning clears an organization's finished jobs; the API's Prune now and the scheduled pruner share it.

type Repository

type Repository interface {
	PublishPluginVersion(context.Context, store.OrganizationTenant, store.PluginVersionInput) error
	ListPluginVersions(context.Context, store.OrganizationTenant, string) (store.PluginSource, []store.PluginVersionSummary, error)
	GetStoredPluginVersion(ctx context.Context, tenant store.OrganizationTenant, name, version string) (store.StoredPluginVersion, error)
	AddPluginZips(ctx context.Context, tenant store.OrganizationTenant, name, version string, zips []store.PluginZip) error
	SetPluginVersionRevoked(ctx context.Context, tenant store.OrganizationTenant, name, version string, revoked bool) error
}

Repository is what an import writes through.

type UpdateChecks

type UpdateChecks interface {
	ClaimPluginUpdateCheck(ctx context.Context, interval time.Duration, includeGitHub bool) (*store.ClaimedPluginUpdateCheck, error)
	RecordPluginUpdateCheck(ctx context.Context, tenant store.OrganizationTenant, id uuid.UUID, latest, tag, checkErr string) error
}

UpdateChecks is where the checker finds due plugins and records results.

type Upstream

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

Upstream reads HashiCorp's release service: api.releases.hashicorp.com for browsing, releases.hashicorp.com for the files an import fetches.

func NewUpstream

func NewUpstream(client *http.Client, api, releases string) *Upstream

NewUpstream reads the release service at the given base URLs.

func (*Upstream) Plugins

func (u *Upstream) Plugins(ctx context.Context) ([]string, error)

Plugins lists the Packer plugins the release service publishes.

func (*Upstream) Versions

func (u *Upstream) Versions(ctx context.Context, product, after string) ([]UpstreamVersion, string, error)

Versions returns one page of a plugin's releases, newest first, and the cursor for the next page ("" on the last). The service pages at most 20.

type UpstreamVersion

type UpstreamVersion struct {
	Version    string
	Created    time.Time
	Prerelease bool
	State      string
	Changelog  string
	Platforms  []string
}

UpstreamVersion is one release of a plugin as the release service lists it.

type VersionOutcome

type VersionOutcome struct {
	Version   string            `json:"version"`
	Outcome   string            `json:"outcome"`
	Error     string            `json:"error,omitempty"`
	Platforms []PlatformOutcome `json:"platforms,omitempty"`
}

VersionOutcome is one requested version of an import.

type Worker

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

Worker runs queued imports one at a time.

func NewWorker

func NewWorker(jobs Jobs, importer *Importer, interval time.Duration, logger *slog.Logger) *Worker

NewWorker polls jobs every interval while idle.

func (*Worker) Run

func (w *Worker) Run(ctx context.Context)

Run works jobs until ctx ends.

func (*Worker) RunOnce

func (w *Worker) RunOnce(ctx context.Context) (bool, error)

RunOnce works at most one job, reporting whether there was one.

Jump to

Keyboard shortcuts

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