syncer

package
v1.15.1 Latest Latest
Warning

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

Go to latest
Published: Jul 25, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FilterAbsent added in v1.13.0

func FilterAbsent(ctx context.Context, s Syncer, secrets []*provider.Secret) ([]*provider.Secret, int, error)

FilterAbsent returns only the secrets whose target-side name (SecretName) is not already present on s, plus how many were skipped. It errors when the target cannot enumerate existing names -- callers must treat that as fatal rather than silently overwriting.

func Fingerprint added in v1.13.0

func Fingerprint(salt []byte, value string) string

Fingerprint returns salted sha256[:8] of a value. Salt keeps it opaque to cross-deployment rainbow tables while staying stable within one deployment.

func LoadDeploySalt added in v1.13.0

func LoadDeploySalt() ([]byte, error)

LoadDeploySalt reads (or first-run creates) a 16-byte deployment salt at ~/.skret/hub-salt with 0600. The salt never leaves the machine.

func Register added in v1.13.0

func Register(typ string, f Factory)

Register wires a target type to its factory. Called from each target's init().

func SaveSyncState added in v1.2.0

func SaveSyncState(s *SyncState) error

SaveSyncState writes the state atomically. The directory is created with 0700 and the file with 0600 so secret-name presence is owner-only readable.

func SecretName added in v1.13.0

func SecretName(key string) string

SecretName is the name a sync target stores a secret under: the last path segment of the provider key, verbatim. Exported so the CLI can show the exact names a sync would write.

func StatePathFor added in v1.2.0

func StatePathFor(target, id string) (string, error)

StatePathFor returns the on-disk path for the given target+id. Exposed for testing; production code uses LoadSyncState/SaveSyncState.

Types

type CloudflareSyncer added in v1.13.0

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

CloudflareSyncer pushes secrets to a CF Worker script (Secrets) or a CF Pages project (production env_vars). Exactly one of worker/pages is set.

func (*CloudflareSyncer) ExistingKeys added in v1.13.0

func (c *CloudflareSyncer) ExistingKeys(ctx context.Context) ([]string, error)

ExistingKeys returns the names of the secrets already set on the worker script. Pages targets cannot enumerate env vars equivalently, so no-overwrite is rejected for them.

func (*CloudflareSyncer) Name added in v1.13.0

func (c *CloudflareSyncer) Name() string

func (*CloudflareSyncer) Sync added in v1.13.0

func (c *CloudflareSyncer) Sync(ctx context.Context, secrets []*provider.Secret) error

type DotenvSyncer

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

DotenvSyncer writes secrets to a dotenv file.

func (*DotenvSyncer) Name

func (d *DotenvSyncer) Name() string

func (*DotenvSyncer) Sync

func (d *DotenvSyncer) Sync(_ context.Context, secrets []*provider.Secret) error

type ExistingLister added in v1.13.0

type ExistingLister interface {
	ExistingKeys(ctx context.Context) ([]string, error)
}

ExistingLister is implemented by syncers whose target can enumerate the names it already holds. Values at these targets are write-only; names are enough to make a sync non-destructive.

type Factory added in v1.13.0

type Factory func(TargetConfig) (Syncer, error)

Factory builds a Syncer from a resolved TargetConfig.

type GitHubSyncer

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

GitHubSyncer pushes secrets to GitHub Actions repository secrets.

func (*GitHubSyncer) ExistingKeys added in v1.13.0

func (g *GitHubSyncer) ExistingKeys(ctx context.Context) ([]string, error)

ExistingKeys returns the names of the Actions secrets already present on the repository (names only -- values are write-only), paginated at 100.

func (*GitHubSyncer) Name

func (g *GitHubSyncer) Name() string

func (*GitHubSyncer) Sync

func (g *GitHubSyncer) Sync(ctx context.Context, secrets []*provider.Secret) error

type Manifest added in v1.13.0

type Manifest struct {
	Namespace   string        `json:"namespace"`
	Env         string        `json:"env"`
	GeneratedAt time.Time     `json:"generated_at"`
	Keys        []ManifestKey `json:"keys"`
}

Manifest is the names-only inventory published to the vault hub. It never contains secret values — only salted fingerprints, names, and per-target presence status.

func BuildManifest added in v1.13.0

func BuildManifest(ns, env string, salt []byte, secrets []*provider.Secret, presence map[string]TargetPresence) *Manifest

BuildManifest computes per-key fingerprint + per-target presence from the current SSM secrets and each declared target's TargetPresence (built by calling ExistingKeys once per target -- see internal/cli/hub.go's targetPresence). GeneratedAt is left zero here — the caller (hub push) stamps it once, so the manifest timestamp is set exactly one place.

Per key, per target:

  • presence.Ok == false -> "unknown" (can't tell)
  • presence.Ok == true, name found in Names -> "present"
  • presence.Ok == true, name not found -> "absent"

type ManifestKey added in v1.13.0

type ManifestKey struct {
	Name        string                    `json:"name"`
	Fingerprint string                    `json:"fingerprint"`
	UpdatedAt   time.Time                 `json:"updated_at"`
	Targets     map[string]ManifestTarget `json:"targets"`
}

type ManifestTarget added in v1.13.0

type ManifestTarget struct {
	Present bool   `json:"present"`
	Status  string `json:"status"` // present | absent | unknown
}

type SyncState added in v1.2.0

type SyncState struct {
	Target  string            `json:"target"`
	ID      string            `json:"id"`
	Hashes  map[string]string `json:"hashes"`
	Updated time.Time         `json:"updated"`
}

SyncState tracks per-secret SHA256(value) hashes for drift detection. Persisted at ~/.skret/sync-state/<target>-<sanitized-id>.json.

func LoadSyncState added in v1.2.0

func LoadSyncState(target, id string) (*SyncState, error)

LoadSyncState reads the state file for target+id, returning an empty state if the file does not exist (first-run case).

func (*SyncState) FilterUnchanged added in v1.2.0

func (s *SyncState) FilterUnchanged(secrets []*provider.Secret) []*provider.Secret

FilterUnchanged returns only the secrets whose hash differs from the state. Secrets not present in the state are included (treated as new).

func (*SyncState) Update added in v1.2.0

func (s *SyncState) Update(secrets []*provider.Secret)

Update records the hashes of the given secrets in-place.

type Syncer

type Syncer interface {
	Name() string
	Sync(ctx context.Context, secrets []*provider.Secret) error
}

Syncer pushes secrets to an external target.

func Build added in v1.13.0

func Build(targets []TargetConfig) ([]Syncer, error)

Build constructs one Syncer per TargetConfig, erroring clearly on unknown types or missing required fields.

func NewCloudflare added in v1.13.0

func NewCloudflare(accountID, worker, pages, token, baseURL string) Syncer

NewCloudflare builds a Cloudflare syncer. baseURL defaults to the public API.

func NewDotenv

func NewDotenv(filePath string) Syncer

NewDotenv creates a dotenv file syncer.

func NewGitHub

func NewGitHub(owner, repo, token, baseURL string) Syncer

NewGitHub creates a GitHub Actions secrets syncer.

type TargetConfig added in v1.13.0

type TargetConfig struct {
	Type        string            // "github" | "cloudflare" | "dotenv"
	Fields      map[string]string // repo / worker / pages / account / file
	Token       string            // resolved from env; never logged
	NoOverwrite bool              // only write keys absent at the target
}

TargetConfig is a resolved sync destination (from .skret.yaml or flags).

type TargetPresence added in v1.13.0

type TargetPresence struct {
	Names map[string]bool
	Ok    bool
}

TargetPresence is what BuildManifest learns about one sync target by calling ExistingKeys once (see internal/cli/hub.go's targetPresence, which builds this map). Ok=false means the target's existing key names could not be determined at all -- either its syncer has no ExistingLister implementation (dotenv always; a Cloudflare Pages target), or ExistingKeys itself failed (network/API error, or the syncer could not even be built, e.g. a missing token) -- in which case every key is reported "unknown" for that target rather than making hub push fail outright. Names holds the existing key names, uppercased, and is only meaningful when Ok is true.

Jump to

Keyboard shortcuts

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