Merge release-1.11 into develop - #10343
Closed
infrahub-github-bot-app[bot] wants to merge 31 commits into
Closed
Conversation
prep release 1.10.9
prep release 1.11.0
…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>
Merge stable into release-1.11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merging release-1.11 into develop after merging pull request #10328.