Skip to content

Bump aquasecurity/trivy-action from a9c7b0f06e461e9d4b4d1711f154ee024b8d7ab8 to ed142fd0673e97e23eac54620cfb913e5ce36c25 - #2

Open
dependabot[bot] wants to merge 141 commits into
mainfrom
dependabot/github_actions/aquasecurity/trivy-action-ed142fd0673e97e23eac54620cfb913e5ce36c25
Open

Bump aquasecurity/trivy-action from a9c7b0f06e461e9d4b4d1711f154ee024b8d7ab8 to ed142fd0673e97e23eac54620cfb913e5ce36c25#2
dependabot[bot] wants to merge 141 commits into
mainfrom
dependabot/github_actions/aquasecurity/trivy-action-ed142fd0673e97e23eac54620cfb913e5ce36c25

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Aug 6, 2026

Copy link
Copy Markdown
Contributor

Bumps aquasecurity/trivy-action from a9c7b0f06e461e9d4b4d1711f154ee024b8d7ab8 to ed142fd0673e97e23eac54620cfb913e5ce36c25.

Commits

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

hunterinvariants and others added 27 commits August 6, 2026 13:09
Dependabot closed its CodeQL bump claiming the action is no longer a dependency,
which is wrong: it is still used for init, autobuild and analyze in codeql.yml
and for upload-sarif in quality.yml. The pin was left on v3.36.2, so the upgrade
silently never happened.

Pin the current v4.37.6 rather than the stale 4.36.2 the closed pull request
carried. The tag is annotated, so the pin is its dereferenced commit; pinning
the tag object would not resolve. The workflows already force Node 24, which is
what the v4 major line expects.
…/actions/upload-artifact-7.0.1

Bump actions/upload-artifact from 6.0.0 to 7.0.1
Record the deployment that puts the console on a public hostname without opening
an inbound port, including the two settings that are easy to miss and expensive
to get wrong.

Without PROMTACT_TRUSTED_PROXIES the connector's loopback address is treated as the
client for every request, so the per-IP login backoff becomes global — one
attacker's failed logins would lock out every customer — and the session cookie
loses its Secure flag because X-Forwarded-Proto is only honored from a trusted
proxy.

Also note why the connector runs as a service rather than a container, and why
127.0.0.1 is preferred over localhost when the server listens on IPv4 only.
… atomic

Two gaps in the metering and observability work.

The metrics endpoint required authentication but not authorization, so the
generic read rule granted it to any authenticated principal — including a
customer's viewer. The counters aggregate every tenant, so a customer could read
the deployment's total decision volume, capacity, backpressure and database
state. That is harmless in a single-tenant install and a cross-tenant leak in
the multi-tenant one now serving publicly. RequiredRoles maps /metrics to admin
and the handler narrows it to the platform operator, matching how provisioning
is already protected. The existing test asserted the viewer got 200, which
codified the leak; it now asserts 403 for both a customer viewer and a
customer's own admin.

Usage metering claimed concurrent decisions increment the counter atomically,
but only the no-directory degradation path was covered. Add a Postgres
integration test that drives 400 concurrent increments and asserts the exact
total: a lost increment is unbilled revenue and a double count overcharges a
customer. It also pins the UTC billing period, separates a different month, and
covers the rejected inputs.
…ss runs

The sequence-aware claim asserted that calls sharing a history key influence
each other while unrelated keys stay isolated, but only the memory bound was
tested — the behavior the claim is actually about was unproven.

Add tests that a chain escalates its own later calls, so splitting a dangerous
sequence into individually harmless-looking steps does not evade the gateway,
and that an unrelated chain scores identically to a clean one, so in a
multi-tenant deployment one customer's activity can never degrade another
customer's verdicts. Also assert a decision carries the reason, request
reference, risk and metadata an audit needs.

Named so the documented acceptance command for the claim picks them up: it now
exercises four tests instead of one.
The gateway computed its verdict locally but then discarded it: if the store
could not persist the resulting alert or action, the handler answered 500. For a
deny that is worse than an outage — a caller that reads an error as "gateway
unavailable" proceeds with the call that was just blocked, turning a storage
incident into a bypass.

Gateway records that cannot be persisted now go to a local append-only journal,
fsynced per record, and the decision is served unchanged. Enforcement is not
weakened while degraded: a deny stays a deny, and an approval requirement stays
one — and because the pending action is not in storage it also cannot be
approved during the outage, which is the safe direction. On the next successful
write, and once a minute while idle, the backlog is replayed into storage; the
journal preserves order and keeps anything that still fails.

The journal refuses new records when full rather than rotating, since discarding
the oldest security records is the loss it exists to prevent; refusals are
counted. Event ingestion and the response API keep failing loudly, because there
the caller needs to know nothing was stored.

Failure injection uses a real write failure rather than a mock: the store is
pointed at a path whose parent cannot be created. Exposed as promtact_degraded_mode,
promtact_decision_journal_depth and promtact_decision_journal_dropped_total, and
promoted from "intentionally not claimed" to claim 6 with its limits stated —
runtime-provisioned identities still need the database to authenticate, and the
journal is host-local.
The test broke the data path before constructing the server, which is not
portable: reading a file through a path component that is itself a file yields
ENOTDIR on Linux but an ordinary not-found on Windows. Construction therefore
succeeded on Windows and failed on Linux, so the suite was green locally and red
on the Linux runner.

Construct the server while the path is still readable — a not-yet-existing
snapshot behaves the same everywhere — and only then replace the parent
directory with a regular file, so every later write fails as an unreachable
database would.
…cated during an outage

Closes the two capabilities the claims document still qualified.

Provenance previously reached the policy engine only from the direct tool-call
API. An MCP tools/call could not carry a fingerprint at all, so calling through
MCP was a way around a pinned tool, and the LangChain connector never sent one.
MCP now reads the claim from the request's _meta, which the protocol reserves
for out-of-band annotation so it cannot be mistaken for a tool argument, with
top-level keys accepted as a fallback; the connector attests per tool. A test
drives the same pinned tool through both surfaces and asserts allow, deny and
gate identically.

Directory identities could not be verified while the database was down, so a
storage incident took every runtime-provisioned agent offline. The directory
adapter now keeps a bounded cache that is consulted only after a lookup fails:
while the database is healthy every request still resolves against it, so a
revoked key stops working immediately and the cache never delays revocation. An
agent never seen before is still rejected, because failing closed is the only
safe answer when the directory is unreachable. This required the store to
separate "no such identity" from "directory unreachable", which it previously
collapsed into a single false.

The added exposure is narrow, and stated in the claim: revocation writes to the
same database, so nothing can be revoked during an outage anyway; only a key
revoked shortly before the outage is covered longer, bounded by
--identity-cache-ttl and disabled by setting it to zero.
A decision could be enforced, audited and reported without any way to tie the
three together afterwards. Every response now carries an X-Correlation-Id, the
same id lands on the audit event, and a caller may supply its own so its trace
joins ours.

The supplied id is untrusted input that ends up in log lines, so it is accepted
only when short and alphanumeric; anything else is replaced by a generated id.
Without that check a caller could inject newlines and forge log entries, which
matters more than usual here because these logs are security evidence.

Structured logging is opt-in via --structured-logs and emits one JSON line per
request with status, duration, principal, tenant and client IP. Query strings
and headers are excluded because they carry tokens. The logging middleware wraps
the chain from the outside so rejected requests are logged too, and the auth
layer reports the resolved principal back to it.
Release the multi-tenant SaaS work that has accumulated since 0.4.0: the
Postgres-backed tenant directory and platform provisioning API, the React
console embedded in the binary, usage metering and Prometheus metrics, enforcement
that survives a storage outage with a reconciling decision journal, tool
provenance on every agent surface, the outage-only identity cache, and
correlation ids with optional structured request logs.
policy.json decides which tools are approved, which principals exist and what
roles they hold, which tool fingerprints are pinned and which agent identities
are registered — and it was loaded from local disk without any integrity check.
An attacker with file access could grant themselves admin or approve a tool, and
nothing would notice. It matters most during an outage, when a restart reads
that file as the only source of those facts.

The policy now carries a detached HMAC signature, verified before parsing so an
altered document never takes effect. With a key configured this fails closed: a
missing signature is an error rather than a way to skip verification, matching
how threat packs already behave. The key is deliberately separate from the
threat-pack key, so a compromised detection-content key cannot also forge
identities. PROMTACT_POLICY_REQUIRE_SIGNED makes a host refuse to start unverified
even before a key is distributed.

Without a key the behaviour is unchanged, so existing deployments keep working.
Add `promtactl sign-policy`, and promote signed snapshots from "intentionally not
claimed" into claim 6.
The validation timer could raise an alert but there was nowhere to send it. A
receiver on the monitored host would be the wrong answer: the alert reports that
something on that host is broken, so it would die exactly when needed.

This Cloudflare Worker runs at the edge, independent of the machine it watches.
It authenticates the sender with a required shared secret compared in constant
time — an unauthenticated endpoint that pages a human is a denial-of-service
target — formats the failed techniques for a human, and fans out to ntfy,
Discord or Slack, each optional. Delivery failures are logged rather than
returned, so a dead downstream cannot make the sender believe the alert was
rejected and retry it forever.
Every endpoint is now reachable both at its original path and under /api/v1.
Mirroring rather than moving is deliberate: the validation suite, the LangChain
connector, the console and the agents already deployed all speak the original
paths, and a hard cut would break them simultaneously for no benefit. New
integrations can pin a version instead.

The rewrite runs before authentication, which is the part that matters.
Authorization matches concrete prefixes such as /api/admin/, so a versioned path
arriving at the auth layer unrewritten would miss those rules and fall through
to the generic read rule — handing customer and key metadata to any viewer. A
test asserts that /api/v1/admin/tenants stays as admin-only as its original.

Unversioned API responses carry RFC 8594 Deprecation and a successor Link, so
integrators can find the migration target without reading a changelog; the old
paths keep working and are not scheduled for removal.

The OpenAPI 3.1 document is embedded and served at /api/v1/openapi.json, so it
describes the deployment being talked to rather than something published
elsewhere. A test asserts it still documents the enforcement surface, since an
endpoint that quietly vanishes from the spec is worse than one never documented.

Also disable Worker preview URLs and document the alert-path verification.
A wrangler-account.json cache file was committed with the Worker. It holds only
the Cloudflare account id and name — no tokens — and the account id already
appears in ordinary dashboard URLs, so nothing needs rotating and rewriting
published history would be disproportionate. Local tool state still does not
belong in the tree, so remove it and ignore the directory.
Requests now carry W3C Trace Context: an incoming traceparent is
continued so an agent's own trace joins the enforcement decision, and
the server span is echoed back on the response.

Spans are exported over OTLP/HTTP JSON to any collector, Tempo or
Jaeger endpoint. The wire format is implemented against the standard
library rather than the OpenTelemetry SDK, which would add roughly
twenty modules including protobuf and gRPC for a feature that is off
unless an endpoint is configured.

Export is asynchronous and bounded. A slow or dead collector adds no
latency to a decision and cannot grow memory without limit; spans past
the queue limit are dropped and counted in promtact_trace_spans_dropped_total.
Identifying which build serves traffic previously meant reading a
symlink on the host. The revision now comes from the Go build info, so
the toolchain stamps it and it cannot drift from the binary the way a
hand-maintained constant can. A dirty working tree is reported as such.
People and machines were the same kind of directory record, which makes
a second factor impossible to require: enforcing it would break every
agent authenticating with an API key. Accounts now declare a kind, and
existing rows become human, so nothing changes on upgrade.

A service account cannot hold a console session. The rule is enforced
twice on purpose — the directory query excludes it, and MintSession
refuses it — so a future login path that resolves an identity some other
way cannot reintroduce a permanent MFA-exempt door. Bearer-key
authentication is untouched, since agents are the reason these accounts
exist.

An unrecognised or missing kind is read as human. Defaulting the other
way would hand any corrupted row the exemption machines carry.

Also adds the schema for TOTP enrolment, spent time steps and recovery
codes, and a TOTP implementation verified against the RFC 6238 test
vectors. It uses the standard library rather than a dependency: the
algorithm is short, and the authentication path is where a compromised
package is worth the most to an attacker.
Login now verifies the credential without issuing anything, so a TOTP
or single-use recovery code can be demanded before a session exists.

Three properties carry the design. The check fails closed: an unreadable
enrolment state refuses the login rather than letting everyone in
without a factor exactly when the database is unhealthy. A spent time
step is claimed in the database, so an intercepted code cannot be
replayed during the rest of its thirty-second window, and concurrent
attempts elect exactly one winner. And the reasons stay
distinguishable — a user told "wrong credentials" when a code was
merely missing will retype their key until the backoff locks them out.

Enrolment is self-service and acts only on the caller's own account, so
every authenticated role can reach it. Demanding admin there would leave
a viewer unable to secure their own login, which in practice means the
tenant never turns MFA on. A pending enrolment stays inert until a code
confirms it, so a mistyped setup cannot lock anyone out, and a confirmed
one cannot be silently replaced by whoever holds a session.

Deprovisioning suspends the account and revokes its keys in one
transaction. Leaving live credentials behind is the usual way an
offboarded identity keeps working.
An identity provider can now create, read, update and offboard directory
accounts over RFC 7643/7644.

The endpoints sit under /api/scim/v2 rather than at the conventional
/scim/v2 root. The authentication middleware only guards /api/ and
/metrics, so a top-level mount would have been served with no
authentication at all — a provisioning API open to the internet. A
regression test now fails if anyone adds one there. Provisioning is also
admin-only for every method; under the generic read rule any viewer
could have enumerated a customer's whole user directory over GET.

The tenant comes from the calling credential and never from the request
body, and it is part of the lookup rather than a check applied
afterwards, so another customer's id resolves to "not found" instead of
confirming that it exists. Roles supplied by the identity provider pass
through the application allowlist, since group membership is
attacker-influenceable and an unmapped value must grant nothing.

Deletion suspends the account and revokes its keys instead of erasing
the record: the requirement is that credentials stop working, and a row
that disappears takes its audit trail with it.

Only the userName equality filter is accepted. Writing a general filter
language would put a parser for attacker-supplied input in front of the
directory for no provisioning benefit — and the first draft here did
accept a compound expression, which the test caught.
A TOTP seed has to be readable to verify a code, so unlike an API key it
cannot be reduced to a hash. It is now sealed instead: each record gets
its own data key, wrapped by a key-encryption key that never reaches the
database, so a leaked dump decrypts nothing on its own. The integration
test asserts against the raw column rather than the API that wrote it.

Rotation adds a key alongside the old one and names a new primary. New
records use it while existing records stay readable, so a rotation is
gradual rather than a migration that must not fail halfway. Removing a
key that records still reference fails loudly and names it — otherwise a
botched rotation surfaces as users mysteriously losing their second
factor, with nothing pointing at the cause.

The key-encryption key sits behind a provider interface so a deployment
can move wrapping into a KMS or HSM without touching the code that reads
or writes secrets. The provider that ships holds keys in process memory
from the environment; what it buys even so is separation of key from
data, which is the property that matters when a backup leaks.

Encryption is opt-in and prior records keep working, but a key that is
configured and rejected stops startup: continuing would write plaintext
while the operator believes the data is encrypted. A short key is
refused at configuration time for the same reason — it produces the
appearance of encryption without the substance.

AES-256-GCM comes from the standard library, so nothing is added to the
dependency tree on the path that protects the secrets.
Token hashes are globally unique in the schema, so the fixed constants
these tests used made them pass on a fresh database and fail on every
run afterwards. That is the worst shape a test can have: it looks green
exactly once, and the failure appears later with no relation to the
change that seems to have caused it.
The README had grown into a 600-line inventory: a 57-item feature list
and every runtime flag with its explanation. That is reference material,
and it was crowding out the two things a reader actually needs first —
what the system does and why it is shaped that way.

The inventory moves to docs/capabilities.md, the flags and file formats
to docs/configuration.md, the endpoints to docs/api.md. What remains is
the problem, the four choices that determine everything else, and a
quick start.

docs/design-decisions.md is new. It records the reasoning behind the
non-obvious choices, the alternatives that were rejected and what each
one costs: why enforcement is inline, why denial has to survive a
storage outage, why service accounts had to exist before MFA could,
why SCIM is mounted under /api/, why three features were implemented
against the standard library instead of taking a dependency.

It also keeps the mistakes: the metrics endpoint that leaked
platform-wide counters to any viewer with a test that codified the leak,
a setting that was parsed and never applied, a failure-injection test
that only failed on Linux, integration tests that passed exactly once,
and MCP tool calls that carried no provenance. The reasoning behind
those is more useful than the fixes.
Nothing removed old release directories, so every deploy that reached a
host left one behind. On a small VM that ends as a deploy failing at 3am
because the disk filled with old copies of the thing being deployed.

The script refuses to act unless it can positively identify the running
release: the "current" symlink must resolve to a directory inside
releases/. If it was replaced by a real directory or the link is
dangling, readlink still succeeds and returns a path matching no
release — at which point every release below the keep count looks safe
to delete, including the running one. It exits instead.

It keeps five releases beyond the live one by default, because
deploy-release.sh rolls back to the previous release when a deploy
fails; pruning to one would take the rollback target away. A keep count
below two is rejected for the same reason.

Dry run by default.
A deployment created before the rename carries the old table prefix,
including the migration ledger. The rename has to happen before that
ledger is read: the new code would otherwise find no ledger, conclude
the database is empty, and create a fresh schema beside the real data —
which is indistinguishable from total data loss to whoever is on call.

That is why this is not a numbered migration. It runs ahead of the
mechanism the numbers live in, inside the same advisory lock, and does
nothing unless the old ledger exists and the new one does not.

Tables and indexes move in one statement. A half-renamed schema is worse
than either end state, because some tables would be found and others
silently recreated empty.

The test builds the situation in a throwaway schema — old prefix,
populated ledger, real rows — and checks that the applied versions and
the data both survive, that nothing is left behind, and that a second
run changes nothing.
It existed to rename an existing deployment's tables in place, which is
not how the change is being made: the database is rebuilt from the
migrations and the data imported into it, so the schema is the one the
migrations produce rather than the one a rename left behind.

Removing it also removes a hazard. It renamed whatever lived in
current_schema(), which is only correct if every connection agrees on
the schema — and database/sql hands queries to a pool, so it does not.
Its own test set the search path on one connection and had the rename
run on another, against the wrong schema.
Bumps [aquasecurity/trivy-action](https://github.com/aquasecurity/trivy-action) from a9c7b0f06e461e9d4b4d1711f154ee024b8d7ab8 to ed142fd0673e97e23eac54620cfb913e5ce36c25.
- [Release notes](https://github.com/aquasecurity/trivy-action/releases)
- [Commits](aquasecurity/trivy-action@a9c7b0f...ed142fd)

---
updated-dependencies:
- dependency-name: aquasecurity/trivy-action
  dependency-version: ed142fd0673e97e23eac54620cfb913e5ce36c25
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot @github

dependabot Bot commented on behalf of github Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Labels

The following labels could not be found: dependencies, github-actions. Please create them before Dependabot can add them to a pull request.

Please fix the above issues or remove invalid values from dependabot.yml.

hunterinvariants added a commit that referenced this pull request Aug 7, 2026
…/actions/upload-artifact-7.0.1

Bump actions/upload-artifact from 6.0.0 to 7.0.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant