Skip to content

Merge last changes from release-1.11 to develop - #10346

Merged
ogenstad merged 33 commits into
developfrom
pog-last-release-1.11-to-develop
Aug 20, 2026
Merged

Merge last changes from release-1.11 to develop#10346
ogenstad merged 33 commits into
developfrom
pog-last-release-1.11-to-develop

Conversation

@ogenstad

@ogenstad ogenstad commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Why

Bring in the last updates from release-1.11 before the git bot starts to target stable directly to develop

Replaces #10343.

What changed

  • All changes from release-1.11
  • A new commit to make the updated version of ty happy: 2c853c0

Review in cubic

wvandeun and others added 30 commits August 19, 2026 15:20
…ig overrides

`memory_cache` and `bus_simulator` each set a `config.OVERRIDE` field and never
put it back. The `dependency_provider.scope(...)` unwinds on teardown, but
`build_cache()` and `build_message_bus()` consult `config.OVERRIDE` *first*, so
the override outlives the class that installed it and every later resolution in
that xdist worker gets the previous class's throwaway adapter.

For the cache that surfaces as

    ResourceNotFoundError: Diff summary for pipeline <uuid> was not found in the cache

in `TestProposedChange::test_run_generators_validate_requested_jobs`. The test
writes the diff summary through a cache built from `config.SETTINGS.cache.driver`
(Redis) and `run_generators` reads it back via `get_cache()`. Once the override
leaks, the write goes to Redis and the read goes to the leftover MemoryCache.

It reads as flaky but it is scheduling: it fails exactly when xdist puts
`test_artifact_regen_e2e.py`, which uses `memory_cache`, on the same worker
earlier in the session. Runs 32238651760 and 32153198842 had both files on gw3
and failed; run 32251034448 had them on gw3 and gw1 and passed.

For the message bus nothing fails today — a stale BusSimulator swallows messages
instead of raising — so it is fixed here before it costs a debugging session.

Save and restore in a `finally`, matching the neighbouring `workflow_local`
fixture and every other override site in the suite.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…class

`setup_task_manager_once` recorded only success, so a Prefect test server that
came up and then stopped responding was retried by every later test class in that
xdist worker.

The retry is not cheap. The setup does not fail fast against an unreachable
server — it blocks on the API until the pytest timeout fires — so each retry cost
the full 300s. In run 32238651760 that turned one broken worker into 46
`Failed: Timeout >300.0s` errors across five test files and pushed the session
into its 1800s limit, with the original httpx.ReadTimeout buried under 45
identical copies.

Remember the failure alongside the success and re-raise it, chained, on every
later call. The worker still fails, but once, in seconds, with the cause attached
to the first error rather than the forty-sixth.

`except BaseException` is deliberate: the pytest timeout raises `Failed`, which
does not derive from `Exception`, and that is exactly the failure worth
remembering.

The once-per-process state moves onto a `TaskManagerSetup` object that takes the
setup callable as a constructor argument, so the tests drive it with recording and
failing doubles instead of patching the module — the adapter pattern the testing
guidelines ask for. `setup_task_manager_once()` keeps its signature and callers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…10306)

* fix(graphql): reject user-supplied branched_from on branch creation

BranchCreate persisted a client-supplied branched_from verbatim, letting a
new branch appear to have been created in the past and expose data since
deleted on all branches. The mutation now rejects the field with an error,
and both branched_from and origin_branch (already restricted to the default
branch) are marked deprecated on BranchCreateInput.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore(frontend): revert spurious gql.tada cache reorder

The @deprecated directives added to BranchCreateInput do not change any
document type, so graphql-cache.d.ts should not have been touched. The
committed version only reordered entries, which no longer matches what
`pnpm codegen:graphql` emits, failing frontend-validate-graphql-types.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(graphql): reject empty branched_from and raise ValidationError

Addresses cubic review feedback on #10306.

A supplied-but-falsy `branched_from` (empty string) slipped past the
truthiness check and blew up later as `TimestampFormatError: Invalid time
format for ` inside the branch-create flow. Check for presence of a
non-null value instead, so every client-supplied value is rejected up
front. An explicit `null` is still accepted: it is equivalent to omitting
the field and rejecting it would break clients that serialize None.

Raise `ValidationError` (HTTP 422, centrally handled) rather than a bare
`ValueError`, matching how the rest of this mutation reports invalid
input.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(graphql): close the same falsy-input hole for origin_branch

`origin_branch: ""` passed the truthiness guard and then overrode the
"main" default on the model, producing a branch whose origin_branch is
empty. Compare against a non-null value so any supplied value other than
the default branch is rejected, and raise ValidationError to match how the
neighbouring branched_from check reports invalid input.

An explicit null on an optional field previously reached the pydantic
model and failed to validate against a non-optional default
(origin_branch, description, sync_with_git). Drop nulls when building the
model so an explicit null behaves like omitting the field.

Rework the BranchCreate input tests onto the dataclass parametrize
pattern, covering both rejected fields and the omitted/null fallbacks.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* add removal version

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…aw TCP probe

Every rabbitmq-diagnostics invocation boots a full Erlang VM, costing
~2.1s of CPU time per check (measured on rabbitmq:4.2.1-management). At
the 1s healthcheck interval this pegs more than two cores per broker
container for the entire life of the stack, and the ~0.3-1s wall time
races against the 1s timeout on loaded CI machines.

check_port_connectivity only verifies that the listener ports accept
TCP connections, so a bash /dev/tcp probe on 5672 provides the identical
readiness signal at ~1ms per check, with no broker log noise (RabbitMQ
does not log connections closed before the protocol header). Exec form
is required because the image's /bin/sh (dash) lacks /dev/tcp support.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rocess-wide

The configured_logging fixture called configure_logging(production=False,
log_level="DEBUG"). That routine is application startup code: it sets the root
log level, replaces the root handler and reconfigures structlog, and undoes none
of it. Called per test it left the root logger at DEBUG for the rest of the xdist
worker, overriding the WARNING level pytest_configure pins, so every later test
in that worker logged a line per Bolt message from the Neo4j driver.

Install only what the assertions need instead: extract the filter installation
from configure_logging as install_traceback_suppression_filter, call that from
the fixture and remove the filter after the yield. The fixture is renamed
traceback_suppression_installed to say what it now does.

Also record the general rule in the backend testing guidelines and the Python
testing agent rules: leave process-global state as you found it, and never call
an application startup routine from a test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…logging state

The three suppression tests pass whether the fixture installs only the filter or
calls configure_logging, since that routine installs the same filter — nothing
committed distinguished them, so the leak could come back unnoticed.

Extract the fixture body into a _traceback_suppression context manager and assert
its contract directly: the Prefect run loggers carry exactly the filter it
installed while it is open, and both their filter lists and the root log level are
back to their previous values once it closes. Driving the context manager rather
than probing state from a later test module keeps the guard hermetic — no
dependence on collection order or on which xdist worker picks the file up.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…n loggers

Extracting install_traceback_suppression_filter left the configure_logging call
site uncovered: dropping it would keep every traceback suppression test passing,
since they install the filter themselves.

Assert instead on what importing infrahub.log already did — its module-level
configure_logging call is the production wiring — so the call site is covered
without a test reconfiguring logging for the rest of the worker.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A docstring should say what the test asserts, not what it deliberately does not
do. The paragraph explaining why the test reads the state left by the import
rather than calling configure_logging again is a note on a choice already made;
the rule it follows is written down in the backend testing guidelines.

The first line still explains why asserting on import-time state is the wiring
assertion, which is the part a reader needs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
test_traceback_suppression_leaves_logging_state_unchanged drives a context
manager and reads logging state — it needs no database, no Prefect flow run and
none of the component suite's fixtures, so it belongs next to the other
infrahub.log tests in the unit suite.

Move the install/remove cycle it drives to tests/helpers/log.py as
traceback_suppression, so the webhook fixture and the guard share one
implementation across suites and any future fixture that installs the filter
inherits the guard. Its docstring keeps the line that says what it does; the
paragraph on why it installs the filter alone rather than calling
configure_logging is the rule the testing guidelines now carry, which the
guidelines point at the helper for.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…nting

`read_flow_runs()` returns at most 200 rows (the Prefect API's default page
size, and the API rejects a larger limit), so once the session's
webhook-process runs fill that page the render test's before/after count
comparison saturates at 200 and can never be true again. That makes the test
fail deterministically whenever `TestWebhookConfigure` lands on the same xdist
worker, which is how five unrelated PRs went red between Aug 13 and Aug 18
with a message blaming server-side parameter rendering.

Identify the run by its id and webhook instead, and assert the rendered
parameters really are the plain strings the test exists to guard.

Delete the webhook automations a test class registers at its teardown: the
Prefect server is session-scoped, so a surviving all-branches automation turned
every event emitted by every later test in the worker into a scheduled
webhook-process run that no worker ever executes. Measured over the webhook
package plus one event-heavy ipam class: 216-243 leftover runs and 233-235s
without the cleanup, 1 run and 182-201s with it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The v1.10.7 release failed in publish-docker-image / sbom (run
31521732131) when `cosign attest` could not write to the Sigstore
transparency log:

    Post "https://rekor.sigstore.dev/api/v1/log/entries":
    giving up after 2 attempt(s)

Rekor was only briefly unavailable — the sign job had succeeded against
the same infrastructure five minutes earlier, and the identical sbom job
passed on the next nightly run with no code change. But cosign retries a
failed log write only twice internally and exposes no knob to raise
that, so a blip that short was enough to fail the release. The fallout
was disproportionate: the SBOM upload step never ran, so v1.10.7 is the
only release since v1.10.0 with no SBOM artifacts, and
repository-dispatch (which needs publish-docker-image) was skipped, so
downstream repos were never notified of the release.

Three changes:

- Wrap cosign sign and both cosign attest calls in a retry() helper:
  five attempts 60 seconds apart, covering a ~4-minute outage. The
  helper takes the command as arguments ("$@", no string/eval layer)
  and is pasted verbatim into the sign and sbom jobs — they run on
  separate runners, so it cannot be shared without a checkout or a
  third-party action in the signing path.

- Upload the SBOM artifacts before attesting them, so a
  transparency-log outage can no longer cost us the SBOMs themselves.
  Attestation failures still fail the job, which is the correct outcome
  for a supply-chain step.

- Set overwrite: true on the SBOM upload. Artifacts are scoped to the
  run rather than the attempt, so with the upload now preceding a step
  that can fail, a re-run would otherwise die at the upload step
  because the artifact name already exists from the earlier attempt.
  Every caller passes a version unique to its invocation, so the only
  artifact this can replace is the same SBOM from a previous attempt of
  the same run.

Verified by extracting both run scripts from the parsed workflow and
executing them against a stubbed cosign: immediate success (1 call, no
sleeps), recovery after 3 failures (exit 0, 3 sleeps), budget
exhaustion (5 calls, 4 sleeps, exit 1), and a terminally failing first
attest stops the script before the second attest runs. The two retry()
bodies are asserted byte-identical, and actionlint passes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…10336)

Bumps the uv group with 5 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [pydantic-settings](https://github.com/pydantic/pydantic-settings) | `2.14.1` | `2.14.2` |
| [python-multipart](https://github.com/Kludex/python-multipart) | `0.0.27` | `0.0.31` |
| [pyjwt](https://github.com/jpadilla/pyjwt) | `2.12.1` | `2.13.0` |
| [cryptography](https://github.com/pyca/cryptography) | `48.0.0` | `50.0.0` |
| [starlette](https://github.com/Kludex/starlette) | `1.2.1` | `1.3.1` |

Bumps the uv group with 2 updates in the /python_testcontainers directory: [pydantic-settings](https://github.com/pydantic/pydantic-settings) and [starlette](https://github.com/Kludex/starlette).


Updates `pydantic-settings` from 2.14.1 to 2.14.2
- [Release notes](https://github.com/pydantic/pydantic-settings/releases)
- [Commits](pydantic/pydantic-settings@v2.14.1...v2.14.2)

Updates `python-multipart` from 0.0.27 to 0.0.31
- [Release notes](https://github.com/Kludex/python-multipart/releases)
- [Changelog](https://github.com/Kludex/python-multipart/blob/main/CHANGELOG.md)
- [Commits](Kludex/python-multipart@0.0.27...0.0.31)

Updates `pyjwt` from 2.12.1 to 2.13.0
- [Release notes](https://github.com/jpadilla/pyjwt/releases)
- [Changelog](https://github.com/jpadilla/pyjwt/blob/master/CHANGELOG.rst)
- [Commits](jpadilla/pyjwt@2.12.1...2.13.0)

Updates `cryptography` from 48.0.0 to 50.0.0
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](pyca/cryptography@48.0.0...50.0.0)

Updates `starlette` from 1.2.1 to 1.3.1
- [Release notes](https://github.com/Kludex/starlette/releases)
- [Changelog](https://github.com/Kludex/starlette/blob/main/docs/release-notes.md)
- [Commits](Kludex/starlette@1.2.1...1.3.1)

Updates `pydantic-settings` from 2.12.0 to 2.14.2
- [Release notes](https://github.com/pydantic/pydantic-settings/releases)
- [Commits](pydantic/pydantic-settings@v2.14.1...v2.14.2)

Updates `starlette` from 1.2.1 to 1.3.1
- [Release notes](https://github.com/Kludex/starlette/releases)
- [Changelog](https://github.com/Kludex/starlette/blob/main/docs/release-notes.md)
- [Commits](Kludex/starlette@1.2.1...1.3.1)

---
updated-dependencies:
- dependency-name: pydantic-settings
  dependency-version: 2.14.2
  dependency-type: direct:production
  dependency-group: uv
- dependency-name: python-multipart
  dependency-version: 0.0.31
  dependency-type: direct:production
  dependency-group: uv
- dependency-name: pyjwt
  dependency-version: 2.13.0
  dependency-type: direct:production
  dependency-group: uv
- dependency-name: cryptography
  dependency-version: 50.0.0
  dependency-type: indirect
  dependency-group: uv
- dependency-name: starlette
  dependency-version: 1.3.1
  dependency-type: indirect
  dependency-group: uv
- dependency-name: pydantic-settings
  dependency-version: 2.14.2
  dependency-type: indirect
  dependency-group: uv
- dependency-name: starlette
  dependency-version: 1.3.1
  dependency-type: indirect
  dependency-group: uv
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Merge stable into release-1.11
Adds a skill that mines GitHub Actions history for flaky tests using
retry outcomes (failed attempt -> green re-run) and cross-PR recurrence
as evidence. A bundled stdlib-only collector caches runs, failed-job
logs, and a longitudinal per-test ledger under ~/ci-cache so successive
invocations build trend data instead of re-querying the GitHub API.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Split main() into focused helpers, use set.update over add-in-loop,
escape the Playwright breadcrumb separator, and add explicit
encodings. Verified against the release-1.11 window: identical
results (180 runs matched, 38 failed jobs) and idempotent ledger.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Split date-range queries: the Actions runs API silently caps listings
  at 1000 results; the first pass over a 1321-run week dropped the
  oldest 321 runs.
- Extract Playwright tests from hyphenated project names
  (e.g. [docs-regression-check]).
- New systemic buckets: runner-oom (exit 137), docker network pool
  exhaustion, actions-download 429, and green-pytest-exit-1
  (session-teardown abort after all tests pass).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An expired log wrote an empty file via gh(..., check=False), and the
st_size == 0 branch re-fetched it on every collection, defeating the
documented never-re-download guarantee. Downloads now distinguish
HTTP 404/410 (log gone: durable empty sentinel, never re-fetched) from
transient gh failures (no file written, warned, retried next run), so
the download condition is a plain exists() check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The sqlite-locked bucket regex only matched the SQLAlchemy-wrapped form
`(sqlite3.OperationalError) database is locked` while the SKILL.md table
documented the raw `sqlite3.OperationalError:` form. In every cached
incident log both renderings appear together (chained traceback), so the
bucket did tag, but a raw-only occurrence is plausible. Match both via
`[):]` and sync the SKILL.md table with the code.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The BUCKETS comment and SKILL.md Step 4 promised that a systemic cascade
is reported as one incident, but report-data.json only annotated per-test
entries with bucket tags — the analyst had to derive incident counts by
hand from failed_jobs_with_tests.json. The report now carries
bucket_incidents (distinct jobs/runs/PRs per bucket), the BUCKETS comment
describes the actual mechanism (tags feed the incident counts and the
Step 4 judgment), and SKILL.md points at the new field.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A zero-byte body on a successful logs API call would have written the
same empty file the expired-log (404/410) sentinel uses, permanently
suppressing retries for that job. A real job log is never empty, so
leave the file unwritten and warn instead; the next collection retries.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Running the skill no longer triggers a Bash permission prompt for the
bundled collect.py invocation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions github-actions Bot added type/documentation Improvements or additions to documentation group/backend Issue related to the backend (API Server, Git Agent) group/frontend Issue related to the frontend (React) group/ci Issue related to the CI pipeline labels Aug 20, 2026
@codspeed-hq

codspeed-hq Bot commented Aug 20, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 13 untouched benchmarks


Comparing pog-last-release-1.11-to-develop (2c853c0) with develop (e5ee9c8)

Open in CodSpeed

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6 issues found across 31 files

Confidence score: 2/5

  • backend/infrahub/graphql/mutations/branch.py can create branches from the literal main instead of the configured default when origin_branch is omitted or null, causing schema mismatches or failed creation; align the model default with the configured branch.
  • .agents/skills/analyzing-ci-flakiness/scripts/collect.py can silently omit runs after GitHub rejects a commit lookup, and it redownloads identical job logs across overlapping windows, making collection both incomplete and inefficient; propagate or surface lookup failures and reuse cached job IDs/logs.
  • .github/workflows/ci-docker-image.yml can overwrite the first SBOM artifact when a reusable workflow is invoked multiple times without distinct versions, losing build output; require a unique invocation key or incorporate the invocation identity into the artifact name.
  • python_sdk is pinned to a stable release lineage rather than the required origin/develop, while the security dependency updates in pyproject.toml appear to need the project's towncrier release metadata; correct the submodule ref and add the required release note fragments.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name=".github/workflows/ci-docker-image.yml">

<violation number="1" location=".github/workflows/ci-docker-image.yml:281">
P2: When this reusable workflow runs twice in one caller run with an omitted or reused `version`, `overwrite: true` silently replaces the first invocation’s SBOM artifact. Require a unique invocation key or include the image digest/job identity in the artifact name while retaining overwrite for reruns.</violation>
</file>

<file name="pyproject.toml">

<violation number="1" location="pyproject.toml:48">
P3: These dependency bumps are security patches (python-multipart fixes a multipart DoS; pyjwt 2.13.0 is a security release) that user-visible behavior on uploads and JWT handling. Per the project's towncrier convention for dependency/security changes, add a `changelog/<issue-id>.security.md` fragment so the next release notes and CHANGELOG.md capture these fixes. Neither changelog/ nor CHANGELOG.md currently references them, so they would silently drop out of the release notes when develop next ships.</violation>
</file>

<file name="backend/infrahub/graphql/mutations/branch.py">

<violation number="1" location="backend/infrahub/graphql/mutations/branch.py:100">
P1: When the configured default branch is not `main`, omitting `origin_branch` or sending `null` still constructs the model with `origin_branch="main"`, so branch creation uses the wrong schema or fails. Set the model's `origin_branch` to `registry.default_branch` before dispatching the workflow.</violation>
</file>

<file name=".agents/skills/analyzing-ci-flakiness/scripts/collect.py">

<violation number="1" location=".agents/skills/analyzing-ci-flakiness/scripts/collect.py:156">
P1: When GitHub rate-limits or rejects a PR commit lookup, `check=False` turns the failure into an empty SHA set and the collector silently drops that PR's runs. Propagate the error or emit a warning and mark collection incomplete; do not treat an API failure as a PR with no commits.</violation>

<violation number="2" location=".agents/skills/analyzing-ci-flakiness/scripts/collect.py:245">
P2: On successive overlapping windows, `collect_failed_jobs` looks only under the current window, so the same job log is downloaded again. Put job logs in a repository-level cache or resolve an existing job ID from prior windows before calling `fetch_job_log`.</violation>
</file>

<file name="python_sdk">

<violation number="1" location="python_sdk:1">
P2: This merge to develop bumps the python_sdk submodule to 99a380ac (tag v1.23.0, merge of "prep-release-1.23.0"), which sits on the stable/release lineage. Per AGENTS.md, the develop branch must pin python_sdk to origin/infrahub-develop, whose head is currently 5a25f46; neither 99a380ac nor the tip commit 2c853c0 is an ancestor of infrahub-develop. After this release merge lands on develop, re-pin the submodule to origin/infrahub-develop.</violation>
</file>

Shadow auto-approve: would not auto-approve because issues were found.

Re-trigger cubic

task: dict | None = None

model = BranchCreateModel(**data)
model = BranchCreateModel(**{key: value for key, value in data.items() if value is not None})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: When the configured default branch is not main, omitting origin_branch or sending null still constructs the model with origin_branch="main", so branch creation uses the wrong schema or fails. Set the model's origin_branch to registry.default_branch before dispatching the workflow.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/infrahub/graphql/mutations/branch.py, line 100:

<comment>When the configured default branch is not `main`, omitting `origin_branch` or sending `null` still constructs the model with `origin_branch="main"`, so branch creation uses the wrong schema or fails. Set the model's `origin_branch` to `registry.default_branch` before dispatching the workflow.</comment>

<file context>
@@ -77,13 +86,18 @@ async def mutate(
         task: dict | None = None
 
-        model = BranchCreateModel(**data)
+        model = BranchCreateModel(**{key: value for key, value in data.items() if value is not None})
         await apply_external_context(graphql_context=graphql_context, context_input=context)
 
</file context>
Suggested change
model = BranchCreateModel(**{key: value for key, value in data.items() if value is not None})
model_data = {key: value for key, value in data.items() if value is not None}
model_data["origin_branch"] = registry.default_branch
model = BranchCreateModel(**model_data)

def pr_head_shas(repo: str, numbers: list[int]) -> dict[str, set[int]]:
sha2pr: dict[str, set[int]] = defaultdict(set)
for n in numbers:
out = gh(["api", f"repos/{repo}/pulls/{n}/commits?per_page=100", "--paginate", "--jq", ".[].sha"], check=False)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: When GitHub rate-limits or rejects a PR commit lookup, check=False turns the failure into an empty SHA set and the collector silently drops that PR's runs. Propagate the error or emit a warning and mark collection incomplete; do not treat an API failure as a PR with no commits.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .agents/skills/analyzing-ci-flakiness/scripts/collect.py, line 156:

<comment>When GitHub rate-limits or rejects a PR commit lookup, `check=False` turns the failure into an empty SHA set and the collector silently drops that PR's runs. Propagate the error or emit a warning and mark collection incomplete; do not treat an API failure as a PR with no commits.</comment>

<file context>
@@ -0,0 +1,410 @@
+def pr_head_shas(repo: str, numbers: list[int]) -> dict[str, set[int]]:
+    sha2pr: dict[str, set[int]] = defaultdict(set)
+    for n in numbers:
+        out = gh(["api", f"repos/{repo}/pulls/{n}/commits?per_page=100", "--paginate", "--jq", ".[].sha"], check=False)
+        for sha in out.split():
+            sha2pr[sha].add(n)
</file context>

infrahub-sbom.spdx.json
infrahub-sbom.cdx.json
retention-days: 90
overwrite: true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When this reusable workflow runs twice in one caller run with an omitted or reused version, overwrite: true silently replaces the first invocation’s SBOM artifact. Require a unique invocation key or include the image digest/job identity in the artifact name while retaining overwrite for reruns.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/ci-docker-image.yml, line 281:

<comment>When this reusable workflow runs twice in one caller run with an omitted or reused `version`, `overwrite: true` silently replaces the first invocation’s SBOM artifact. Require a unique invocation key or include the image digest/job identity in the artifact name while retaining overwrite for reruns.</comment>

<file context>
@@ -258,3 +278,37 @@ jobs:
             infrahub-sbom.spdx.json
             infrahub-sbom.cdx.json
           retention-days: 90
+          overwrite: true
+
+      - name: Attest SBOMs
</file context>

print(f"[collect] WARN jobs {r['id']}/{attempt}: {exc}", file=sys.stderr)
continue
for job in jobs:
log_path = win_dir / "joblogs" / f"{job['id']}.log"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: On successive overlapping windows, collect_failed_jobs looks only under the current window, so the same job log is downloaded again. Put job logs in a repository-level cache or resolve an existing job ID from prior windows before calling fetch_job_log.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .agents/skills/analyzing-ci-flakiness/scripts/collect.py, line 245:

<comment>On successive overlapping windows, `collect_failed_jobs` looks only under the current window, so the same job log is downloaded again. Put job logs in a repository-level cache or resolve an existing job ID from prior windows before calling `fetch_job_log`.</comment>

<file context>
@@ -0,0 +1,410 @@
+            print(f"[collect] WARN jobs {r['id']}/{attempt}: {exc}", file=sys.stderr)
+            continue
+        for job in jobs:
+            log_path = win_dir / "joblogs" / f"{job['id']}.log"
+            if not log_path.exists():
+                fetch_job_log(repo, job["id"], log_path)
</file context>

Comment thread python_sdk
@@ -1 +1 @@
Subproject commit f9e28cfd5958946759f113fd9fe29422adc8fcea
Subproject commit 99a380ac145cb549687bc2b8030cf5edf2f5a492

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This merge to develop bumps the python_sdk submodule to 99a380ac (tag v1.23.0, merge of "prep-release-1.23.0"), which sits on the stable/release lineage. Per AGENTS.md, the develop branch must pin python_sdk to origin/infrahub-develop, whose head is currently 5a25f46; neither 99a380ac nor the tip commit 2c853c0 is an ancestor of infrahub-develop. After this release merge lands on develop, re-pin the submodule to origin/infrahub-develop.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At python_sdk, line 1:

<comment>This merge to develop bumps the python_sdk submodule to 99a380ac (tag v1.23.0, merge of "prep-release-1.23.0"), which sits on the stable/release lineage. Per AGENTS.md, the develop branch must pin python_sdk to origin/infrahub-develop, whose head is currently 5a25f46; neither 99a380ac nor the tip commit 2c853c0 is an ancestor of infrahub-develop. After this release merge lands on develop, re-pin the submodule to origin/infrahub-develop.</comment>

<file context>
@@ -1 +1 @@
-Subproject commit f9e28cfd5958946759f113fd9fe29422adc8fcea
+Subproject commit 99a380ac145cb549687bc2b8030cf5edf2f5a492
</file context>

Comment thread pyproject.toml
"starlette-exporter>=0.23,<0.24",
"prometheus-client>=0.25,<0.26",
"python-multipart==0.0.27", # Required by FastAPI to upload large files
"python-multipart==0.0.31", # Required by FastAPI to upload large files

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: These dependency bumps are security patches (python-multipart fixes a multipart DoS; pyjwt 2.13.0 is a security release) that user-visible behavior on uploads and JWT handling. Per the project's towncrier convention for dependency/security changes, add a changelog/<issue-id>.security.md fragment so the next release notes and CHANGELOG.md capture these fixes. Neither changelog/ nor CHANGELOG.md currently references them, so they would silently drop out of the release notes when develop next ships.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At pyproject.toml, line 48:

<comment>These dependency bumps are security patches (python-multipart fixes a multipart DoS; pyjwt 2.13.0 is a security release) that user-visible behavior on uploads and JWT handling. Per the project's towncrier convention for dependency/security changes, add a `changelog/<issue-id>.security.md` fragment so the next release notes and CHANGELOG.md capture these fixes. Neither changelog/ nor CHANGELOG.md currently references them, so they would silently drop out of the release notes when develop next ships.</comment>

<file context>
@@ -45,10 +45,10 @@ dependencies = [
     "starlette-exporter>=0.23,<0.24",
     "prometheus-client>=0.25,<0.26",
-    "python-multipart==0.0.27", # Required by FastAPI to upload large files
+    "python-multipart==0.0.31", # Required by FastAPI to upload large files
     "asgi-correlation-id==4.2.0", # Middleware for FastAPI to generate ID per request
     "bcrypt>=4.1,<4.2", # Used to hash and validate password
</file context>

@ogenstad
ogenstad marked this pull request as ready for review August 20, 2026 11:39
@ogenstad
ogenstad requested review from a team as code owners August 20, 2026 11:39
@ogenstad
ogenstad merged commit 00e5b35 into develop Aug 20, 2026
66 checks passed
@ogenstad
ogenstad deleted the pog-last-release-1.11-to-develop branch August 20, 2026 11:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

group/backend Issue related to the backend (API Server, Git Agent) group/ci Issue related to the CI pipeline group/frontend Issue related to the frontend (React) type/documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants