Software Factories on AWS

Self-hosted platform for standing up and running software factories on AWS: complete DevSecOps environments with secure delivery pipelines, supply-chain controls, compliance evidence and multi-tenant governance — in minutes, not months.

Plugin Installing

Using plugins other organizations published: what an install is, which versions it lets resolve, and the policy that decides what your org may install at all.

Highlights

Overview

The plugin ecosystem is the directory of plugins published by the platform and by other organizations. To use one of those plugins in your pipelines, your organization installs its listing.

A listing is a plugin name published by a publisher, written @acme/terraform-plan in the UI and { publisher: acme, name: terraform-plan } in a pipeline.

This page is for pipeline authors and org admins. To put your own plugin in the directory, see Plugin Publishing.

How it works

  1. You find a listing — in the public directory at /plugins, or the in-app catalog which also shows your org’s state for each one.
  2. Your consumption policy is consulted. It may allow the install outright, require an admin’s approval, or refuse the listing entirely.
  3. The install records a version policy — which of the listing’s versions are allowed to resolve for your pipelines.
  4. A pipeline references the plugin, qualified with a publisher or not. An unqualified name resolves through your own org first; see Resolution order.
  5. Create and update check every reference. Anything not installed, blocked by policy or unresolvable is reported per step in one response.
  6. Synth resolves the concrete version and pins it by digest, so the build runs exactly the image that was approved.
  7. Nightly rescans keep watching. A version that later picks up a fixable Critical is flagged, which warns by default and can be made to block.

Configuration

As an org admin:

  1. Set the consumption policy — allowed trust tiers, blocked listings, whether an advisory at or above a chosen severity blocks, and whether implicit Official installs stay on. Needs plugin_installs:manage plus a step-up. See Consumption policy.
  2. Decide whether installs need approval, per trust tier. An install of an approval-required tier made without plugin_installs:manage becomes a pending request instead.
  3. Configure plugin security notifications so blocked builds and new Criticals reach someone. See Plugin security notifications.
  4. Check for shadowing before rolling the catalog out: GET /api/plugins/shadowing lists every own-org plugin name that shadows a listing.

As a pipeline author:

  1. Install the listing you need, or request it if your policy requires approval.
  2. Choose a version policy on the install — see Version policies.
  3. Reference it in your pipeline, qualifying with publisher when you mean the listing rather than a same-named plugin of your own. See Referencing plugins.
  4. Read the errors literally if create refuses — Errors you may see maps each code to the fix.

Finding plugins

A listing is a plugin name published by a publisher, written @acme/terraform-plan in the UI and { publisher: acme, name: terraform-plan } in a pipeline.

Trust tiers

Every listing carries its publisher’s trust tier. The badge always sits beside the plugin icon.

Tier Who publishes it Installed by default
Official The platform’s own catalog (publisher pipeline-builder) Yes, implicitly
Verified Team and Enterprise publishers approved by the system org No
Community Any signed-in organization, each listing approved by the system org No
Unverified Anonymous submissions that passed automated checks and human moderation No

The tier is part of each image’s signature. At lookup the platform checks that the signed tier and publisher still match the publisher’s current tier and handle. If they don’t, the step fails with 409 IMAGE_VERIFICATION_FAILED.

Community submissions (Unverified)

Unverified listings come from people without an account, through the directory’s Submit a plugin page (see Submitting without an account). They’re all published under the platform’s community publisher, as community/<name>.

To allow Unverified listings (needs plugin_installs:manage and a recent re-authentication):

  1. Open dashboard → Plugins → Policy.
  2. Add Unverified to Allowed tiers.
  3. Leave it in Tiers that need approval (the default), so each install is decided by an admin under Plugins → Approvals.
  4. Leave it out of Tiers that get secrets (the default), so these plugins never receive your secrets. A step that declares secrets still runs, without them, and warns PLUGIN_SECRETS_WITHHELD.

Allowing the tier doesn’t install anything: each community plugin still needs its own install, and, with the defaults above, an admin’s approval. To keep particular community listings out entirely, add them to blockedListings.

A pipeline references a community plugin with the community publisher: plugin: { publisher: community, name: <name> }. If the submitter later claims the listing with an account, it moves to their publisher like a transfer and its images are re-signed with the new publisher.

Installs

Install a listing from its catalog page (Install). Installing needs plugins:install, which members, admins and owners hold.

Installing is free on every plan and doesn’t count against any quota.

Version policies

Each install has a version policy. It decides which versions a new synth may resolve to.

Policy Resolves to Example (installed at 1.4.2)
pinned Exactly the installed version 1.4.2 only
patch New patch versions (~installed) 1.4.x
minor (default) New minor and patch versions (^installed) 1.x
latest The newest stable version, but never across a version the publisher marked breaking 1.x, and further until a breaking version

A new major version never flows in on its own. You’re told it’s available (with the changelog and the vulnerability delta), and you upgrade when you choose.

A pipeline step can narrow the install’s range with filter.version (see Referencing plugins). It can never widen it: a version outside the install’s range fails with PLUGIN_NOT_INSTALLED, reason version_outside_install.

Upgrading

Upgrading means changing an install’s version or its policy (the install’s Upgrade action, or PATCH /api/plugins/installs/:id). It needs plugins:install. For a listing whose tier requires approval, moving across a major or breaking version, or switching the policy to latest, needs plugin_installs:manage. The install views say so ahead of time: needsApproval: true on a catalog entry or an install means such a change needs an approver for you. A team can’t change or remove an install it inherits from its root organization.

Without plugin_installs:manage you request the change instead (POST /api/plugins/installs/:id/change-requests with { version?, versionPolicy?, note? }). The request is stored on the install as its one pending change (pendingChange on the install), your organization’s approvers are notified (N11), and they approve it (the change is applied, re-checked against your policy at that moment) or reject it with a reason under Plugins → Approvals. You’re told the outcome (N12). A change that needs no approval is refused as a request — apply it directly.

Deployed pipelines keep running the image digest they were synthesized with. A new version reaches a pipeline on its next synth.

Which versions never resolve

Vulnerability scans and rescans

Every plugin version’s image is scanned when it’s built, and rescanned every night. A build with more fixable Critical findings than the instance allows never gets stored (see Scan gates). A finding is fixable when a fixed version of the affected package is known. The plugin list, plugin details, the directory’s versions and supply-chain tabs and the Publisher page show:

A flagged version still resolves by default. Lookup answers with a warning, which synth, pipeline-manager and the pipeline editor show:

VULN_FLAGGED: trivy@1.4.0 has 2 fixable Critical findings — rebuild or upgrade

When the operator sets PLUGIN_BLOCK_ON_NEW_CRITICAL=true, flagged versions are skipped instead. A version range, latest or the default resolves to the newest satisfying version that isn’t flagged, the same way advisory-blocked versions are skipped. An exact version or digest pin to a flagged version fails with 409 PLUGIN_VERSION_VULN_BLOCKED, and the message names the fix. This applies to your organization’s own plugins and to listings.

Your organization decides who is told about rescan findings under Settings → Organization → Plugin security notifications (see Notifications).

Implicit Official installs

Every organization can use Official plugins (publisher pipeline-builder) without installing them. This is an implicit install:

Referencing plugins

A pipeline step names its plugin. A publisher makes the reference qualified.

# Your org's plugin, else your parent org's, else the Official listing
plugin: { name: trivy }

# Only acme's listing, only through your install, narrowed to 1.x
plugin: { publisher: acme, name: terraform-plan, filter: { version: '^1' } }

# The Official listing, named explicitly
plugin: { publisher: pipeline-builder, name: trivy }

Resolution order

Unqualified ({ name: trivy }):

  1. your organization’s own plugin of that name;
  2. for a team, its parent organization’s shared (public) plugin;
  3. the Official listing pipeline-builder/<name>, through your install: an explicit install, else the implicit one.

Qualified ({ publisher: acme, name: … }): only acme’s listing, and only through an install. Your own plugins are never considered. publisher: pipeline-builder names the Official listing.

public visibility only shares a plugin with your organization and its teams. It never reaches another organization, including the system org’s plugins. Only listings do.

Shadowing

If your organization has its own plugin with the same name as an Official listing, your plugin wins for unqualified references. This is shadowing. The platform tells you about it:

To use the Official listing instead, add publisher: pipeline-builder to the step, or rename or delete your plugin.

What pipeline create and update check

Creating or updating a pipeline (in the UI, the API, the CLI or bulk) resolves every plugin reference the way synth does, and refuses the pipeline with 400 TEMPLATE_CONTRACT_VIOLATION and the per-step reasons (details.steps[].refusal) when a qualified reference, or an unqualified one that falls back to an Official listing:

An unqualified reference that matches nothing at all is not refused (it may be created as a placeholder).

The plugin contract (requiredMetadata, requiredVars) is checked for listed versions too.

At synth

Consumption policy

Your organization’s consumption policy decides what your pipelines may use. It never affects the ecosystem or other organizations. Edit it under dashboard → Plugins → Policy. Changing it needs plugin_installs:manage (admins and owners) and a recent re-authentication. Every change is audited (org.plugin-install-policy.update).

Field Values Default Effect
allowedTiers Official, Verified, Community, Unverified Official + Verified Listings from other tiers can’t be installed and don’t resolve (PLUGIN_BLOCKED_BY_POLICY, reason tier).
requireApprovalTiers the same Community + Unverified Installing a listing from these tiers, without plugin_installs:manage, creates a pending request.
secretsAllowedTiers the same Official + Verified Listings from other tiers get no secrets, even if their spec declares them. Lookup removes them and warns PLUGIN_SECRETS_WITHHELD.
blockOnAdvisory critical, high, never critical Versions with a published advisory at or above this severity don’t resolve (reason advisory).
officialInstalls implicit, explicit implicit explicit turns off implicit Official installs, so every Official listing must be installed on purpose (through the approval flow, if it applies). Meant for regulated organizations.
blockedListings list of publisher/name empty These listings don’t resolve and can’t be installed, including Official ones (reason blocked_listing).

No safety control is plan-gated. Every plan gets the full policy.

A compliance rule can express the same limits, when you need an audited “never” rather than a setting.

Teams

Field How the team’s and root’s values combine
allowedTiers Intersection (only tiers both allow)
requireApprovalTiers Union
secretsAllowedTiers Intersection
blockOnAdvisory The stricter level
officialInstalls explicit wins
blockedListings Union

Approvals

Holders of plugin_installs:manage see pending requests under Plugins → Approvals, with the listing, tier, version policy and requester. Approve activates the install; Deny closes it. The requester is told either way.

For a team, the approvers are the team’s holders of plugin_installs:manage; if there are none, the root org’s; if nobody holds it, the owners.

Notifications

Notices go to your organization only. Publishers never learn who installed their plugin.

# When Who How
N11 An install is requested Org approvers In-app + email, immediate (email opt-out ecosystem.installs.email)
N12 Your request is approved or denied The requester In-app + email
N13 A new version is available outside an install’s range Org approvers In-app; weekly email digest. A breaking major is sent at once. Includes the changelog and vulnerability delta.
N27 An installed listing moved to a new version within its range Org approvers In-app; weekly email digest, with the changelog and vulnerability delta
N14 A listing you use is deprecated or unmaintained Installing orgs In-app + email
N26 A listing or version you use was paused by its publisher Installing orgs In-app
N8 A listing or version you use was suspended, yanked or taken down Installing orgs In-app + email, immediate, with the reason
N30 A plugin version was blocked at build: it couldn’t be scanned, or it has fixable Critical findings Your plugin security recipients In-app + email + webhook, immediate
N31 A rescan found new Critical or High findings in a plugin version Your plugin security recipients In-app + email + webhook; follows your digest setting, and sent once per version and set of findings

“Installing orgs” means organizations with an active explicit install, plus, for Official listings, organizations whose pipelines use the listing through the implicit install. The notice goes to each organization’s approvers.

Plugin security notifications

N30 and N31 go where your organization says, under Settings → Organization → Plugin security notifications. Anyone with plugins:read can see the settings; changing them needs org:settings.

Setting Default What it does
Recipients The uploader and everyone who can write plugins Or only the members you choose.
Rescan findings On Turn off to stop N31. Blocked versions (N30) are always sent.
Rescan delivery Immediately Or a daily or weekly digest. N30 is never batched.
Webhook URL None An https URL that gets each notice as JSON. With a signing secret, every delivery carries X-PB-Signature: sha256=<HMAC>. The secret is never shown again once saved.
External address None One address outside your organization, such as a security team’s mailbox. Saving it emails that address a confirmation link, valid for 24 hours and usable once. The link opens a page with a Confirm address button, so mail scanners that open links can’t confirm it. The address gets nothing until it’s confirmed. You can resend the link or remove the address.

Send test sends a test notice to every configured channel, so you can check the webhook and the addresses before a real notice.

Reviews and ratings

Anyone can read reviews on a plugin’s public page (Reviews tab). To write one, sign in: guests see Write a review as a sign-in link that brings them back to the tab.

How the score works

The score is a Bayesian average: every plugin starts at 3.5 stars, worth 10 votes, so a handful of reviews can’t swing it. Verified-use reviews count fully and other reviews count half. The page shows the score, the number of ratings, the star distribution and a Recent versions score over the last two minor versions. Reviews waiting for moderation, and removed ones, don’t count. The directory’s Top rated and Most installed sorts use these numbers, which are refreshed on every review and every 15 minutes. Installs count organizations with an install or a pipeline that uses the plugin; the count of organizations actively running it is shown only from 5 upward.

Limits and moderation

Each organization can post 20 new reviews a day, and so can each network address. Writes are also throttled per person. A review is held for moderation instead of published when it has more than three links, when a burst of reviews from organizations that haven’t used the plugin arrives on one listing, or after reports. Held reviews are invisible to everyone except you: your review shows awaiting moderation. If a moderator removes it, you’re told why (notice N18) and can’t edit it any more.

# When Who How
N15 A review is posted or edited on your listing Publisher managers In-app; email batched hourly per listing (opt-out ecosystem.reviews.email)
N16 The publisher replied to your review The review author In-app + email (opt-out ecosystem.reviews.email)
N18 A moderator removed your review The review author In-app + email, with the reason
N19 A review was reported as a security issue Publisher managers and moderators In-app + email, immediate, private

PLUGIN_REVIEWS_ENABLED=false makes reviews read-only on an instance (PLUGIN_REVIEWS_DISABLED).

Health score

Every listing carries a health score from 0 to 100. It’s a quick read on how well a plugin is looked after, shown as a Health badge on directory cards and plugin pages (good at 80 and above, fair from 50, poor below). The plugin page’s Health panel lists each signal, its score and its share of the total.

Signal Weight How it scores
Runtime success (30 days) 25 Share of the plugin’s steps that succeeded across every organization in the last 30 days. Counted only after 20 runs.
Known vulnerabilities 20 The latest listed version’s scan: 1 with no critical or high findings, minus 0.5 per critical and 0.1 per high, never below 0. Left out until the version is scanned.
Freshness 15 The age of the latest release (full marks up to 90 days, falling to zero at 540), averaged with the age of its base image (full marks up to 60 days, zero at 365) when the base image’s build date is known.
Signed image 10 The listed version has an image digest and the platform’s signature.
Smoke test declared 10 The spec declares a smokeTest.
README and license 10 Half for a README, half for a license.
Rating 10 The Bayesian rating out of 5. Counted only after 3 ratings.

A signal without enough data is left out and the remaining weights are scaled up to 100, so a new plugin isn’t marked down for having no runs or reviews yet. With fewer than three signals there is no score at all. Scores are recomputed every 15 minutes, with the review and install numbers.

Audit

Install and policy actions are recorded in your organization’s audit log, with affectedOrgId = your organization: plugin.install.create (no approval needed), plugin.install.request, plugin.install.approve, plugin.install.deny, plugin.install.upgrade (details.from / details.to), plugin.install.change-request, plugin.install.change-approve / plugin.install.change-reject (an approval-gated change a member asked for, and its decision), plugin.install.remove (details.withdrawn for a withdrawn request) and org.plugin-install-policy.update (the changed fields, before and after). The audit page’s Ecosystem quick filter shows them. See Audit Events.

API

All routes are under /api and need a signed-in caller.

Method Endpoint Permission Purpose
GET /plugins/catalog?q=&category=&installed= plugins:read The catalog with your install state
GET /plugins/listings/:publisher/:name/install-state plugins:read One listing’s install state and versions
GET /plugins/installs?status=&implicit= plugins:read Your installs, optionally with the implicit Official ones
POST /plugins/installs plugins:install { publisher, name, versionPolicy?, version? } → 201, status active or pending_approval
PATCH /plugins/installs/:id plugins:install Upgrade: change the version or policy
DELETE /plugins/installs/:id plugins:install Uninstall, or withdraw a pending request
POST /plugins/installs/:id/approve plugin_installs:manage Approve a pending request
POST /plugins/installs/:id/deny plugin_installs:manage Deny a pending request
POST /plugins/installs/:id/change-requests plugins:install { version?, versionPolicy?, note? } → 201 { changeRequest }: request a change that needs an approver
GET /plugins/installs/change-requests plugin_installs:manage { changeRequests: [{ installId, listing, from, to, requestedBy, requestedAt, note }] }, oldest first
POST /plugins/installs/:id/change-requests/approve plugin_installs:manage Apply the pending change → { install }
POST /plugins/installs/:id/change-requests/reject plugin_installs:manage { reason? } → { install }: drop the pending change
GET /plugins/install-policy plugins:read Your policy and the effective (merged) one
PUT /plugins/install-policy plugin_installs:manage + step-up Save your policy
GET /plugins/shadowing plugins:read Your plugins that shadow an Official listing
GET /plugins/listings/:publisher/:name/review-state plugins:read Your review, your votes and reports, and whether you may review or reply
POST /plugins/listings/:publisher/:name/reviews plugins:read + a person { rating, title?, body?, version? } → 201
PATCH /plugins/reviews/:id plugins:read + a person Edit your review
DELETE /plugins/reviews/:id plugins:read + a person Delete your review
PUT / DELETE /plugins/reviews/:id/helpful plugins:read + a person Mark, or unmark, a review helpful
POST /plugins/reviews/:id/report plugins:read + a person { category: spam\|abuse\|off_topic\|security, reason? }

The catalog entries and install state also carry rating ({ score, count } or null) and installCount. Anonymous readers use GET /api/public/plugins/:publisher/:name/reviews?sort=helpful|recent|highest|lowest&rating=&cursor=&limit= (published reviews only, display names only).

POST /plugins/lookup and GET /plugins/find accept publisher in the filter. The answer’s plugin carries publisher, publisherTier, listingId, imageRepository, source (org or listing) and install (explicit, implicit or null). warnings may include PLUGIN_SHADOWS_LISTING, PLUGIN_SECRETS_WITHHELD, LISTING_UNMAINTAINED, PLUGIN_DEPRECATED and PLUGIN_YANKED.

GET /plugins/plugin-usage counts unqualified references by name and qualified ones by publisher/name.

AI pipeline generation

AI generation offers your installed listings and the implicit Official ones. It writes publisher on a step for any non-Official listing. Plugins it creates on the fly never take the name of a listed plugin; install the listing instead.

Errors you may see

Code Status Meaning
PLUGIN_NOT_INSTALLED 403 The reference needs an install. details.reason: not_installed, pending_approval, denied, official_explicit (your policy turned off implicit Official installs) or version_outside_install (the step asks for a version outside the install’s range).
PLUGIN_BLOCKED_BY_POLICY 403 Your consumption policy refuses it. details.reason: tier, blocked_listing or advisory.
PLUGIN_UNAVAILABLE 409 The listing or version can’t be used. details.reason: yanked, suspended or paused (no new installs).
PLUGIN_NAME_LISTED 409 A plugin created on the fly can’t take a listed plugin’s name. Install the listing instead.
IMAGE_VERIFICATION_FAILED 409 The image’s signature, or its signed tier and publisher, doesn’t verify.
PLUGIN_VERSION_VULN_BLOCKED 409 You pinned a version a rescan flagged, and the instance blocks flagged versions (PLUGIN_BLOCK_ON_NEW_CRITICAL). The message names the fix. Move to a newer version, or use a range.
REVIEW_SELF_PROMOTION 403 You can’t review, or vote on reviews of, your own organization’s plugins.
PLUGIN_REVIEWS_DISABLED 403 Reviews are read-only on this instance (PLUGIN_REVIEWS_ENABLED).
HUMAN_SESSION_REQUIRED 403 Reviews, votes, reports and replies need a person signed in, not an access key or service account.
RATE_LIMIT_EXCEEDED 429 Too many reviews. details.reason: org_daily_limit means your organization posted 20 today.
DUPLICATE_ENTRY 409 You already reviewed this plugin (edit it instead), or already reported this review.