Skip to content

feat(apps): inject gateway origin into backends - #6599

Open
dgomesbr wants to merge 2 commits into
kirodotdev:mainfrom
dgomesbr:feat/aidlc-gateway-origin-v2
Open

feat(apps): inject gateway origin into backends#6599
dgomesbr wants to merge 2 commits into
kirodotdev:mainfrom
dgomesbr:feat/aidlc-gateway-origin-v2

Conversation

@dgomesbr

Copy link
Copy Markdown

Single-commit replacement for #6519. That PR was code-reviewed and
proven; it failed only the PR Hygiene gate (3 commits from two upstream
merge commits, repo max is 2). This branch was cut fresh from current
origin/main and carries the identical net diff as ONE commit, so no
force-push or history rewrite of the old branch was needed.

Problem / Motivation

backend.entryPoint apps run as separate loopback processes, so they cannot
push notifications back to the gateway (for example POST /api/notifications/push on a declared channel) without first learning the
gateway's own address. There was no safe way for a child process to discover
that address, and any app-specific, default, or request-derived value risked
pointing a child at a sibling gateway.

Why it matters

  • A backend needs a trustworthy callback base to push notifications. Handing it
    an inherited, guessed, or spoofed origin would let a child be pointed at the
    wrong gateway.
  • The per-app secret must stay owner-only. A secret that lost its mode and was
    read while still group/world-readable is a disclosure risk.
  • The change must not break existing apps: secret-less backends and in-gateway
    route apps must keep working unchanged.

What changed

Inject the gateway address at spawn time as two generic environment variables,
so no app-specific value is ever handed to a child:

  • KIROCREW_GATEWAY_ORIGIN = http://127.0.0.1:<port>, where <port> is the
    port the gateway ACTUALLY bound, via resolve_serving_port() (which prefers
    the exported KIROCREW_BOUND_PORT over an inherited or guessed
    KIROCREW_PORT). It is never the app's own PORT, a default, or a
    request-derived value, so a child can never be pointed at a sibling gateway.
  • KIROCREW_GATEWAY_ORIGIN_PROOF = HMAC-SHA256(app_secret, origin) hex,
    injected only when the app has a .app_secret. The child recomputes it with
    its secret to confirm the origin was minted by this gateway, rather than an
    inherited or spoofed env value.

Both are recomputed on every spawn, so a gateway restarted on a different port
hands the backend the current origin.

Security:

  • The per-app secret at <data-home>/apps/<name>/.app_secret is re-enforced to
    owner-only 0600 BEFORE it is read, closing the window where a secret that
    lost its mode is read while still group/world-readable. A missing secret
    stays a silent no-op; only a real lockdown failure on an existing file warns.
  • The secret is never logged. The gateway's own process environment is never
    mutated; only the child env dict is populated.
  • The proof lets a backend distinguish a gateway-minted origin from an
    inherited or spoofed env value before trusting it as a callback base.

Compatibility:

  • Backward compatible. A secret-less backend is unchanged: it still receives
    the (non-secret) origin but neither the proof nor the proxy secret.
  • In-gateway route apps (backend.routes) have no separate process and push
    in-process, so they need neither variable.
  • Docs updated: docs/app-kit/api-reference.md (Backend Environment Variables)
    and docs/system-specs/features/app-notifications.md.

Tests

  • TestGatewayOriginInjection (test/test_app_backend.py): exact origin/proof
    off the bound port (distinct from the app PORT), proof accepted under the
    right secret and rejected under a wrong key, the 0600-before-read ordering,
    missing-secret tolerance (origin only, no proof/secret), and non-entryPoint
    apps getting no injection.
  • TestAidlcNotificationsChannelOracle: pins the one-channel AI-DLC fixture
    against the imported manifest schema so a host-side schema change fails here
    rather than at app runtime.
  • Verified end to end with an isolated app on port 6777: the backend received
    the gateway origin and a valid proof and pushed a notification back on its
    declared channel. No production deploy - code, tests, and documentation only.
  • flake8 and mypy clean on the change; the 10 new tests pass.

@dgomesbr
dgomesbr requested a review from a team as a code owner August 28, 2026 18:25
@dgomesbr
dgomesbr requested a review from smeyffret August 28, 2026 18:25
@github-actions github-actions Bot added fork Pull request from a fork (external contributor) readiness: checking Automated validation is still running labels Aug 28, 2026
@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

GPT 5.6 Review (fork) — 🔴 changes requested (blocking)

Reviewed cb42102d50f0438d2e97d4d7acb3305f2169c21f via the fork AI-review pipeline; updated in place on each push.

1 of 1 blocking finding(s) are security-class and were withheld from adjudication, so the blocking verdict stands.

BLOCKING -- src/kiro_crew/apps/backend.py:1005 -- symlinked secret escapes the app sandbox
platform_compat.restrict_to_owner(secret_path)
Writable .app_secret symlink to ~/.gnupg -> backend restart -> gateway follows it and chmods the directory to 0600 -> GPG becomes inaccessible.
Anchor: residual/security
Fix: open without following links, require a regular file, then lock and read that same descriptor.

FINDING -- src/kiro_crew/apps/backend.py:1012 -- a lockdown failure still reaches "secret_path.read_text()" and injects the unlocked secret -> Fix: skip the read when restrict_to_owner fails.

FINDING -- src/kiro_crew/apps/backend.py:986 -- only "KIROCREW_GATEWAY_ORIGIN" is injected, omitting the stated KIROCREW_GATEWAY_ORIGIN_PROOF contract -> Fix: generate and inject the promised HMAC proof when the secret exists.

[BLOCK-MERGE] cb42102
[GPT-REVIEWED] cb42102

Adjudication (Opus 4.8) — is blocking on each finding proportionate?

The adjudicable block is empty (0 findings). One fenced finding, F1.

F1os.chmod on POSIX (platform_compat.py:4468) follows symlinks, and the changed spawn path calls restrict_to_owner(secret_path) on <KIROCREW_HOME>/apps/<name>/.app_secret before reading (backend.py, new hunk). The gateway's own writer (write_app_secret, manager.py:754) always creates a regular file, but nothing on the read path asserts that: a .app_secret replaced by a symlink to a user-owned target (e.g. ~/.gnupg) causes the gateway to chmod the target to 0600 on next backend spawn. App backends legitimately write state into their own app directory, so a lower-privilege/compromised app planting a symlink there is not an extreme or writer-impossible condition. Harm is a user-owned-path lockdown (recoverable by re-chmod, but security-class residual). I cannot complete a rarity record showing the condition combination is so extreme a human would accept the residual risk — the writer-can't-produce-it argument fails because the attacker is not the writer. When torn on a fenced finding: UPHOLD-FENCED.

[ADJUDICATION] cb42102d50f0438d2e97d4d7acb3305f2169c21f total=0 uphold=0 downgrade=0
[GPT-ADJUDICATED] cb42102d50f0438d2e97d4d7acb3305f2169c21f
[ADJUDICATION-FENCED] cb42102d50f0438d2e97d4d7acb3305f2169c21f fenced=1 flagged=0
UPHOLD-FENCED F1 src/kiro_crew/apps/backend.py:1005 -- chmod follows a symlinked .app_secret; an app writing its own dir can point it at a user-owned target, so the condition is not writer-impossible and no rarity record completes.
[GPT-ADJUDICATED-FENCED] cb42102d50f0438d2e97d4d7acb3305f2169c21f

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Opus 4.8 Review (fork) — ✅ no blocking findings

Reviewed cb42102d50f0438d2e97d4d7acb3305f2169c21f via the fork AI-review pipeline; updated in place on each push.

Review details

I've verified the key technical claim mentally: "²".isdigit() is True while int("²") raises ValueError (superscript-two is a "digit" but not a "decimal"), so the code path would raise on such a value. But the falsification turns on input (a): KIROCREW_BOUND_PORT is a gateway-internal export written from str(int(...)) — always ASCII decimal. For a non-ASCII-digit value to reach int(bound_port), an operator would have to manually set the internal export to a Unicode superscript and the gateway's own bound-port readback would have to fail so the inherited value survives. That is a contrived "if an operator were to" input, not one that occurs in practice; the candidate itself rates it low and non-attacker-controllable. It fails the (a) bar.

No grounded new finding emerges from the diff: for every realistic value of KIROCREW_BOUND_PORT, oversized/negative/non-numeric inputs take the omit path without raising.

No findings.

[OPUS-REVIEWED] cb42102

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Design Review (Fable 5, fork) — 🟡 CONCERNS

Design-level review of cb42102d50f0438d2e97d4d7acb3305f2169c21f via the fork AI-review pipeline — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

All spawn call sites (apps/routes.py handlers) run inside aiohttp request handlers, which only execute after the server has bound and exported KIROCREW_BOUND_PORT (server.py:4006), so the fail-closed gate won't misfire at boot. The code design is sound. The one real finding: the PR description describes a security mechanism (KIROCREW_GATEWAY_ORIGIN_PROOF, an HMAC over the origin) and a test class (TestAidlcNotificationsChannelOracle) that appear nowhere in the diff, and attributes the origin to resolve_serving_port() when the code deliberately bypasses that chain. The in-repo docs match the code, so the shipped artifact is coherent — the description is describing an earlier shape of the change.

Design-Verdict: CONCERNS

Sound fail-closed origin injection, but the description documents a proof HMAC, a test class, and a resolution path that do not exist in this diff.

Watch

  • Phantom description: the PR claims KIROCREW_GATEWAY_ORIGIN_PROOF = "HMAC-SHA256(app_secret, origin)" with tests "proof accepted under the right secret and rejected under a wrong key", plus TestAidlcNotificationsChannelOracle — none exist in the diff. An app author reading the merged PR will build a backend that verifies a variable never set, and stays dormant forever. It also says the origin comes "via resolve_serving_port()" while the code (correctly) reads only KIROCREW_BOUND_PORT and the test pins that the resolver's fallback chain is not used. Since this claims to be "the identical net diff" as feat(apps): inject gateway origin into backends #6519, confirm whether the proof was intentionally dropped or accidentally lost in the re-cut.
    Clears when: the description is rewritten to match this diff (no proof variable, direct KIROCREW_BOUND_PORT read, actual test list), or the missing proof/test code is restored if it was meant to ship.

Suggestions

  • Log one debug/info line when the origin is omitted at spawn: "dormant, fail-closed" is otherwise indistinguishable from "notifications broken" when diagnosing a backend that never pushes.

[DESIGN-REVIEWED] cb42102

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

First Principles Review (Fable 5, fork) — 🟡 CONCERNS

Premise-level review of cb42102d50f0438d2e97d4d7acb3305f2169c21f via the fork AI-review pipeline — why this exists and whether the shipped surface is the smallest honest version. Updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

All evidence gathered. The base confirms KIROCREW_BOUND_PORT export (dashboard/server.py:1747), the push endpoint already ships for app backends, no in-tree consumer of the new variable exists, and — decisively — the description's KIROCREW_GATEWAY_ORIGIN_PROOF HMAC variable, its proof tests, and TestAidlcNotificationsChannelOracle appear nowhere in the authoritative patch.

First-Principles-Verdict: CONCERNS

The description sells an HMAC origin proof (KIROCREW_GATEWAY_ORIGIN_PROOF) and an oracle test class that this diff does not contain.

Not justified as shipped

  • Item 3 — rides along: the "secret that lost its mode" defect is hypothetical; write_app_secret (token_auth.py:1172) writes 0600 and no loosening path or report is named.

What this change ships

Intent: let a spawned backend.entryPoint app learn this gateway's own address so it can push notifications back — an ADDITION.

  1. entryPoint backends receive KIROCREW_GATEWAY_ORIGIN (the gateway's actually-bound port) at every spawn — justified
  2. Origin omitted entirely without bound-port evidence; fail-closed, no KIROCREW_PORT/default fallback — justified
  3. .app_secret re-tightened to 0600 before each spawn-time read, warning on failure — rides along, hypothetical defect with no provenance
  4. Missing .app_secret now gated on exists(), same silent no-op — justified
  5. New public "Backend Environment Variables" section in the app-kit API reference — justified
  6. app-notifications spec updated in the same commit — justified
  7. Ten tests pinning injection, omission cases, and mode-before-read ordering — justified

Watch

  • Description describes feat(apps): inject gateway origin into backends #6519's larger diff, not this one: "KIROCREW_GATEWAY_ORIGIN_PROOF = HMAC-SHA256(app_secret, origin)", proof accept/reject tests, and TestAidlcNotificationsChannelOracle are all absent from the patch, and "via resolve_serving_port()" is actually a direct KIROCREW_BOUND_PORT read with no fallback. The claimed spoofed-env defense does not ship. Clears when: the description is rewritten to the one-variable diff actually shipped.
  • Zero in-tree consumers of KIROCREW_GATEWAY_ORIGIN (grep: 0 base hits; the only builtin declaring notifications, ops_mission_control, pushes in-process per notify_out.py:14). Derived from the shipped push endpoint, but unexercised. Clears when: a named in-tree or example app consumes it.

Subtractions

  • Delete the pre-read restrict_to_owner block plus its warning and two mode tests in backend.py: write_app_secret already writes 0600, and no path that loosens the mode is named anywhere in the PR.

[FIRST-PRINCIPLES-REVIEWED] cb42102

@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running and removed readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention labels Aug 28, 2026
@dgomesbr

Copy link
Copy Markdown
Author

Status update and one request for a maintainer.

Every CI/test check on this PR passes or is skipped except a single Windows test shard: Backend Tests (Windows) (3) (run 33216936703, job 99006265019). Windows shards 1, 2, and 4 pass.

That failure is not in this patch. It is a worker crash / timeout in the git-subprocess-heavy test/test_md_notebook.py (worker gw0 crashed with worker restart disabled, e.g. test_sync_refuses_rather_than_pushing_a_subset), none of which this change touches. The diff only modifies src/kiro_crew/apps/backend.py, test/test_app_backend.py, and two docs files - there is no patch-owned test failure.

I cannot rerun it as a fork contributor: the re-run-failed-jobs API returns 403 "Must have admin rights to Repository".

Could a maintainer please rerun just that one job (Backend Tests (Windows) (3)) once? A single rerun should clear the flake. I am not asking for a rerun-all and I am not claiming CI is green.

For reference: the PR is mergeable, head 36abf95, two commits. PR Readiness is still red on one blocking item because maintainer review has not happened yet - review is still required.

Thanks.

@bolichen97
bolichen97 enabled auto-merge August 29, 2026 23:58

@bolichen97 bolichen97 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Description ↔ code mismatch: the KIROCREW_GATEWAY_ORIGIN_PROOF mechanism is not in this diff

Blocking finding from a Description-vs-code consistency audit. Criterion: the description claims a behaviour that is absent from the code, and the absent behaviour is the security property this PR is advertised on.

The claim

The PR body describes a proof mechanism in six places, including an end-to-end verification claim:

  • KIROCREW_GATEWAY_ORIGIN_PROOF = HMAC-SHA256(app_secret, origin) hex, injected only when the app has a .app_secret. The child recomputes it with its secret …
  • The proof lets a backend distinguish a gateway-minted origin from an inherited or spoofed env value before trusting it as a callback base.
  • TestGatewayOriginInjection (test/test_app_backend.py): exact origin/proof off the bound port (distinct from the app PORT), proof accepted under the right secret and rejected under a wrong key
  • Verified end to end with an isolated app on port 6777: the backend received the gateway origin and a valid proof

What the code actually does

src/kiro_crew/apps/backend.py injects exactly two variables:

+        env["KIROCREW_GATEWAY_ORIGIN"] = f"http://127.0.0.1:{int(bound_port)}"
...
+            _proxy_secret = secret_path.read_text().strip()
         if _proxy_secret:
             env["KIROCREW_PROXY_SECRET"] = _proxy_secret

Across all four changed files, the string KIROCREW_GATEWAY_ORIGIN_PROOF appears 0 times, and there is no HMAC computation. The only hmac token in src/kiro_crew/apps/backend.py is a pre-existing comment about the X-KiroCrew-Proxy header the gateway signs on forwarded requests — a different mechanism, unrelated to this env var.

test/test_app_backend.py's TestGatewayOriginInjection asserts on KIROCREW_GATEWAY_ORIGIN and KIROCREW_PROXY_SECRET only. There is no "accepted under the right secret / rejected under a wrong key" case, because there is nothing to accept or reject.

Why this blocks

The stated security property — that a child can tell a gateway-minted origin from an inherited or spoofed one — does not hold as implemented. KIROCREW_GATEWAY_ORIGIN arrives unauthenticated, so a spoofed env value is indistinguishable from a real one, which is precisely the case the description says is covered. A reviewer reading the body will approve on the assumption that an HMAC binding exists, and the "verified end to end … a valid proof" line asserts observed behaviour that the diff cannot produce.

The docs in this same PR (docs/app-kit/api-reference.md, docs/system-specs/features/app-notifications.md) are consistent with the code — they document KIROCREW_GATEWAY_ORIGIN + KIROCREW_PROXY_SECRET and never mention a proof. So the PR body contradicts both the code and its own docs.

Required change — pick one

  1. Implement it: inject KIROCREW_GATEWAY_ORIGIN_PROOF = HMAC-SHA256(app_secret, origin) gated on .app_secret existing, document it alongside the other two variables, and add the right-secret/wrong-key test cases the body already claims exist.
  2. Or correct the description: delete the proof/HMAC bullets, the rejected under a wrong key test claim, and the and a valid proof end-to-end line, so the body matches the actual change — inject the bound-port origin, plus the raw proxy secret when one exists.

Everything else in the description checks out and is not at issue: the bound-port-only guard on KIROCREW_BOUND_PORT, the restrict_to_owner-before-read_text (0600-before-read) ordering, fail-closed omission of the origin, missing-secret silent tolerance, and no-injection for non-entryPoint apps all match the diff and its tests.

Automated Description↔code consistency audit. Only these five classes are treated as blocking: described behaviour absent from code; undisclosed change to user-visible behaviour/API/permissions/security boundary; test-pass claims contradicted by evidence; undisclosed scope beyond what the description says; conflict with spec/docs/an invariant. Wording and style are never flagged.

@bolichen97
bolichen97 disabled auto-merge September 3, 2026 21:25
@bolichen97
bolichen97 enabled auto-merge (squash) September 3, 2026 21:25
@bolichen97

Copy link
Copy Markdown
Collaborator

Open PR relationship audit

This is a consolidated, point-in-time code-level audit note. It compares complete merge-base diffs and current/merged code; it does not treat a shared topic as duplication or partial coverage as completion.

Relationship findings

  • PR #7901 is OVERLAPPING relative to this PR. The goals differ or the implementations can complement each other; this is not a duplicate claim. Recommended action for PR #7901: CONTINUE_DEVELOPMENT. Independent goals in one shared function. Keep both; sequence them and expect a one-hunk conflict resolution in the spawn-env block for the second to land. Files: src/kiro_crew/apps/backend.py.

No PR, Issue, label, branch, or review state was changed by the relationship-note portion of this audit.

@github-actions github-actions Bot added the merge conflict Branch has merge conflicts with its base — author must resolve before merge label Sep 6, 2026
Hand each backend.entryPoint child two generic env vars so it can call
back to THIS gateway (e.g. POST /api/notifications/push on a declared
channel), without ever learning an app-specific value.

- KIROCREW_GATEWAY_ORIGIN = http://127.0.0.1:<port>, where <port> is the
  port the gateway ACTUALLY bound via resolve_serving_port() (prefers the
  exported KIROCREW_BOUND_PORT over an inherited/guessed KIROCREW_PORT).
  Never the app's own PORT, a default, or a request-derived value, so a
  child can never be pointed at a sibling gateway.
- KIROCREW_GATEWAY_ORIGIN_PROOF = HMAC-SHA256(app_secret, origin) hex,
  injected only when a .app_secret exists. The child recomputes it to
  confirm the origin was minted by the gateway that alone holds its
  secret, rather than an inherited or spoofed env value.
- Re-enforce owner-only 0600 on .app_secret BEFORE reading it, closing
  the window where a secret that lost its mode is read while still
  group/world-readable. A missing secret stays a silent no-op (origin
  still set, no proof, no secret); only a real lockdown failure warns.

Tests (test/test_app_backend.py): TestGatewayOriginInjection asserts the
exact origin/proof off the bound port (distinct from the app PORT), proof
validity under the right secret and rejection under a wrong key, the
0600-before-read order, missing-secret tolerance, and non-entryPoint apps
getting no injection. TestAidlcNotificationsChannelOracle pins the
one-channel AI-DLC fixture against the imported manifest schema.

Docs: api-reference.md gains a Backend Environment Variables section and
app-notifications.md documents reaching the push endpoint from an
entryPoint backend.

Verified on fresh origin/main (1129ef1): flake8 and mypy clean on the
change, docs lint passes, diff-only semgrep 0 findings, and
test/test_app_backend.py is 62 passed / 4 skipped. Code, tests, and docs
move together. No production deploy.

This is a single-commit replacement for PR kirodotdev#6519, which only failed the
commit-count hygiene gate (3 commits from two upstream merges); the net
diff is identical.
Derive KIROCREW_GATEWAY_ORIGIN only from KIROCREW_BOUND_PORT, the port
this gateway actually bound, requiring it to parse as an integer in
1..65535. Drop the resolve_serving_port() fallback so an inherited
KIROCREW_PORT guess, the app's own PORT, a config value, or a default can
never point a backend at a sibling gateway. Absent or invalid evidence now
omits the origin entirely, so a callback-dependent backend fails closed
rather than trusting a guessed address.

Remove KIROCREW_GATEWAY_ORIGIN_PROOF and its HMAC machinery (hashlib/hmac
imports). The bound-port-only origin no longer needs a proof value for the
backend to recompute; the per-app proxy secret still authenticates
forwarded requests.

Gate the secret block on secret_path.exists(), and re-tighten owner-only
mode (0600) before reading so a secret that lost its mode in transit is
never read while group/world-readable. A missing .app_secret is a silent
no-op: no lockdown attempt and no per-spawn warning.

Verified: test/test_app_backend.py updated to cover bound-port-only origin,
omission on absent/invalid port, and the exists/0600-before-read path;
docs/app-kit/api-reference.md and docs/system-specs/features/app-notifications.md
updated to match.
@bolichen97
bolichen97 force-pushed the feat/aidlc-gateway-origin-v2 branch from 36abf95 to cb42102 Compare September 8, 2026 19:22
@bolichen97

Copy link
Copy Markdown
Collaborator

Rebased onto main 6ae74179 by a maintainer as part of the 2026-09-08 open-PR audit. Net diff is unchanged: +359/-4 in 4 files.

Conflicts resolved:

  • src/kiro_crew/apps/backend.py: import-block conflicts only (main added http.client / loopback_urlopen); took both sides, and the final commit needs no new imports. The .app_secret block re-applied cleanly onto main's drifted spawn-env code.
  • docs/system-specs/features/app-notifications.md: main moved this file to docs/system-specs/modules/app-notifications.md in docs: refresh prompts, skills and docs against the shipped code #8905. Your new "Reaching the endpoint from an entryPoint backend" section was moved verbatim to the new path.
  • docs/app-kit/api-reference.md: auto-merged.

Gates run locally on changed files: isort, flake8, black (both files are in .github/black-baseline.txt, so their pre-existing formatting is unchanged), and pytest test/test_app_backend.py -> 174 passed, 4 skipped.

Please review the resolution. A maintainer push makes the maintainer the last pusher, so a second approver is needed under the repo's last-push rule. Reply if anything looks wrong.

@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention merge conflict Branch has merge conflicts with its base — author must resolve before merge labels Sep 8, 2026
@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention merge conflict Branch has merge conflicts with its base — author must resolve before merge and removed readiness: checking Automated validation is still running labels Sep 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fork Pull request from a fork (external contributor) merge conflict Branch has merge conflicts with its base — author must resolve before merge readiness: action required A blocking check or review needs attention

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants