Skip to content

feat(ipc): resolve calling user on IPC calls via the registered auth backend - #291

Merged
traoreera merged 2 commits into
mainfrom
ipc-auth-with-plugin
Oct 6, 2026
Merged

traoreera merged 2 commits into
mainfrom
ipc-auth-with-plugin

Conversation

@traoreera

@traoreera traoreera commented Oct 6, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • IPC calls (supervisor.call() / TrustedBase.call_plugin()) can now resolve the calling user via the registered AuthBackend, separately from the existing HTTP-route RBAC. New AuthResolverMiddleware, get_current_principal(), resolve_principal_from_request() — resolution only, nothing is enforced yet.
  • @action(name, permissions=None) — optional declarative permissions list, mirroring @route's existing param.
  • @schema stays fully independent of @action (usable standalone or stacked, either order).
  • Depend on the now-published xcdk>=0.2.0 / xcorecli>=2.3.0 instead of only the vendored xcore/sdk/ fallback; trimmed makefile targets superseded by xcorecli; dropped stale tracked report files under reports/.
  • Version bump to 2.8.0 + CHANGELOG entry.

Test plan

  • poetry run pytest tests/unit tests/integration -q — 1387 passed, 1 pre-existing unrelated skip
  • poetry run mkdocs build --strict — clean (pre-existing unrelated warnings only)
  • make lint-check — passed
  • pre-commit hooks (trim whitespace, bandit, test & coverage) passed on both commits

Summary by Sourcery

Add best-effort authenticated-user resolution to IPC calls while preparing declarative per-action authorization and modernizing project dependencies and tooling.

New Features:

  • Resolve IPC calling principals through the registered authentication backend and expose them to plugin code across nested calls.
  • Add optional declarative permissions metadata to the @action decorator while keeping it independent from @schema.
  • Adopt published xcdk and xcorecli packages as runtime dependencies.

Enhancements:

  • Keep IPC principal resolution best-effort and separate from existing plugin resource permissions and HTTP-route RBAC.
  • Make authentication documentation cover the updated backend contract and IPC user-resolution flow.

Build:

  • Bump the project version to 2.8.0 and refresh the lockfile dependencies.

Documentation:

  • Document the IPC authentication-resolution middleware, principal access, decorator behavior, and updated authentication APIs.

Chores:

  • Remove obsolete makefile management targets and stale generated report files.

…backend

Separate from the existing HTTP-route RBAC (RBACChecker): a new
AuthResolverMiddleware sits in the plugin-call pipeline, just before
PermissionMiddleware. It resolves a `principal` (AuthPayload) from a
raw `token` via AuthBackend.decode_token() registered by an auth
plugin, or passes through an already-resolved `principal` without
contacting the backend again.

PluginSupervisor._dispatch() exposes it for the duration of the call
via a ContextVar (same pattern as the tenant-id ContextVar), read
with get_current_principal() — never by mutating the plugin's shared
PluginContext. The generic HTTP endpoint resolves it best-effort from
the incoming request; TrustedBase.call_plugin() forwards the current
principal automatically on nested plugin-to-plugin IPC calls, with no
re-decoding. Resolution only — nothing enforces it yet.

Also: @action(name, permissions=None) gains an optional declarative
permissions list (fn._xcore_action_permissions), mirroring @route's
existing permissions param — the hook a future per-action permission
check will read. @Schema stays fully independent, usable standalone
or stacked with @action in either order.

Depend on the now-published xcdk (>=0.2.0) and xcorecli (>=2.3.0)
packages instead of only the vendored xcore/sdk/ fallback. Trim
makefile targets now superseded by xcorecli (plugin clone/symlink,
deploy, service management). Drop stale generated report files under
reports/ that shouldn't have been tracked.
IPC principal resolution via the registered auth backend,
@action(permissions=...), xcdk/xcorecli as real dependencies.
@sourcery-ai

sourcery-ai Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Reviewer's Guide

This release adds non-enforcing authenticated-principal resolution to the HTTP and IPC execution paths, propagates identity safely through nested async calls, introduces declarative action permission metadata, and updates dependencies, tooling, documentation, and release artifacts for version 2.8.0.

Sequence diagram for authenticated principal resolution across HTTP and nested IPC calls

sequenceDiagram
    participant C as HTTPClient
    participant R as Router
    participant A as AuthBackend
    participant S as PluginSupervisor
    participant M as AuthResolverMiddleware
    participant PA as PluginA
    participant PB as PluginB

    C->>R: POST /plugin/action
    R->>A: extract_token(request)
    A-->>R: token
    R->>A: decode_token(token)
    A-->>R: AuthPayload
    R->>S: call(..., principal=AuthPayload)
    S->>M: pipeline(..., principal=AuthPayload)
    M->>S: next_call(..., principal=AuthPayload)
    S->>PA: _dispatch()
    PA->>PA: get_current_principal()
    PA->>S: call_plugin(plugin_b, action, principal)
    S->>M: pipeline(..., principal=AuthPayload)
    M->>S: next_call(..., principal=AuthPayload)
    S->>PB: _dispatch()
    PB->>PB: get_current_principal()
Loading

File-Level Changes

Change Details Files
Add best-effort principal resolution and propagation across HTTP-to-IPC and nested plugin calls.
  • Introduce AuthResolverMiddleware to reuse an existing principal or decode a raw token without enforcing access.
  • Resolve HTTP request credentials before dispatch and pass the resulting principal through supervisor calls.
  • Store the principal in a per-task ContextVar and expose it via get_current_principal().
  • Automatically forward the current principal from TrustedBase.call_plugin() to nested IPC calls.
  • Document the flow and keep it separate from plugin ACL middleware and HTTP RBAC enforcement.
xcore/kernel/api/auth.py
xcore/kernel/api/contract.py
xcore/kernel/api/router.py
xcore/kernel/middlewares/auth_resolver.py
xcore/kernel/middlewares/__init__.py
xcore/kernel/runtime/middlewares/__init__.py
xcore/kernel/runtime/supervisor.py
doc/advanced/middleware.md
doc/sdk/api/auth.md
Extend action metadata with declarative per-action permissions while preserving independent schema decoration.
  • Add the optional permissions argument and store it on the decorated function.
  • Normalize schema input handling into a shared helper.
  • Allow @action and @schema to be used independently or stacked in either order; enforcement remains deferred.
  • Update decorator documentation with the metadata and composition behavior.
xcore/sdk/decorators.py
doc/sdk/api/decorators.md
Align packaging and project maintenance with published SDK/CLI dependencies and the 2.8.0 release.
  • Add bounded xcdk and xcorecli dependencies and update the lockfile.
  • Bump the project version and add changelog coverage.
  • Remove superseded make targets, make lint commands non-fatal, and rename the documentation server target.
  • Delete stale generated report artifacts and update benchmark output.
pyproject.toml
poetry.lock
makefile
doc/changelog.md
xcore_bench_report.json
reports/bandit.json
reports/bandit.txt
reports/bench_report_data.json
reports/report_analysis.md
reports/sandbox_dynamic_security_analysis_2026-09-28.md
reports/technical_debt_remediation_2026-08-10.md
reports/technical_debt_remediation_verification_2026-08-11.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

⚠️ PR très large (8400 lignes modifiées). Pensez à la découper en plusieurs PRs plus petites pour faciliter la revue.

@github-actions github-actions Bot added documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file core config labels Oct 6, 2026
@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-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.

Hey - I've found 8 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="xcore/kernel/api/auth.py" line_range="78" />
<code_context>
+    Principal (sub/roles/permissions) résolu pour l'appel IPC en cours via
+    l'AuthBackend enregistré — None si aucun token n'a été transmis ou résolu.
+    """
+    return _current_principal.get()
+
+
</code_context>
<issue_to_address>
**Nested plugins trust altered identity**

When plugin code mutates the current principal before making a nested call, `get_current_principal()` exposes a mutable `AuthPayload`, and `TrustedBase.call_plugin()` forwards the same object. Mutations alter the current identity and reach downstream plugins, allowing forged roles or permissions and cross-call interference.

Make principals immutable or return and forward defensive deep copies at both boundaries.

Also at `xcore/kernel/api/contract.py:171`, `xcore/kernel/runtime/supervisor.py:348`.
</issue_to_address>

### Comment 2
<location path="xcore/kernel/runtime/supervisor.py" line_range="348" />
<code_context>
+        # Même pattern que le ContextVar tenant : posé une fois ici pour l'appel
+        # en cours, lu par get_current_principal() dans le plugin — jamais de
+        # mutation d'un objet PluginContext partagé entre requêtes concurrentes.
+        principal_token = _current_principal.set(principal)
+        try:
+            # Les services du plugin sont déjà wrappés (TenantAwareDB/Cache) au
</code_context>
<issue_to_address>
**Background tasks retain caller identity**

When a handler starts a detached task during an authenticated IPC call and that task later makes a nested plugin call, `_dispatch()` resets `_current_principal` only in its own task context; the detached task keeps its inherited copy. `TrustedBase.call_plugin()` then forwards that stale principal, so the downstream plugin sees the original user after the request ends.

Prevent detached tasks from retaining or forwarding the request principal after `_dispatch()` completes.

Also at `xcore/kernel/api/contract.py:171`.
</issue_to_address>

### Comment 3
<location path="makefile" line_range="122-129" />
<code_context>
 	@poetry run bandit -r xcore/ -f txt  -o "$(REPORT_DIR)/bandit.txt" 2>>/dev/null || true
 	@echo "Rapports : $(REPORT_DIR)/bandit.json / bandit.txt"

-security-check: ## Vérifications rapides (.env, mots de passe en dur)
-	@if git ls-files | grep -q "\.env$$"; then \
-		echo "❌ .env est tracké par git !"; exit 1; \
-	else echo "✅ .env correctement ignoré"; fi
-	@if grep -rn "password\s*=\s*[\"'][^\"']*[\"']" xcore/ 2>/dev/null; then \
-		echo "❌ Mots de passe potentiels détectés !"; \
-	else echo "✅ Aucun mot de passe en dur"; fi
-

 # ============================================================
</code_context>
<issue_to_address>
**CI security check becomes a no-op**

When the CI security job or `ci-security` target runs, `ci-security` and the GitHub security job still invoke `make security-check`, but the target's recipe is removed while `security-check` remains in `.PHONY`; Make therefore succeeds without checking whether `.env` is tracked or passwords are hard-coded.

Restore the `security-check` recipe or remove its callers and replace the checks with an equivalent active target.
</issue_to_address>

### Comment 4
<location path="xcore/kernel/api/auth.py" line_range="92-94" />
<code_context>
+    backend = get_auth_backend()
+    if backend is None:
+        return None
+    token = await backend.extract_token(request)
+    if token is None:
+        return None
+    return await backend.decode_token(token)
</code_context>
<issue_to_address>
**Backend errors abort anonymous calls**

When the registered backend raises while extracting or decoding a request token, `resolve_principal_from_request()` lets the backend exception escape, so the generic HTTP endpoint never reaches `supervisor.call()` and returns an error instead of dispatching anonymously.

Catch extraction and decoding errors in the resolver and return `None` so the call proceeds without a principal.

Also at `xcore/kernel/api/router.py:168`.
</issue_to_address>

### Comment 5
<location path="xcore/kernel/runtime/supervisor.py" line_range="348" />
<code_context>
+        # Même pattern que le ContextVar tenant : posé une fois ici pour l'appel
+        # en cours, lu par get_current_principal() dans le plugin — jamais de
+        # mutation d'un objet PluginContext partagé entre requêtes concurrentes.
+        principal_token = _current_principal.set(principal)
+        try:
+            # Les services du plugin sont déjà wrappés (TenantAwareDB/Cache) au
</code_context>
<issue_to_address>
**Sandboxed plugins lose caller identity**

When an authenticated call targets a sandboxed plugin, `PluginSupervisor._dispatch()` sets `_current_principal` in the supervisor process, but the sandbox worker receives only the action and payload. Its `get_current_principal()` therefore returns `None`, so sandboxed plugin code cannot access the caller identity.

Propagate the principal to the sandbox worker and set it in the worker’s context for the call.
</issue_to_address>

### Comment 6
<location path="makefile" line_range="50-52" />
<code_context>
 	@$(MAKE) clean
 	@poetry run python -m uvicorn main:app --reload --host 0.0.0.0 --port 8000

-st: ## Lancer en mode production (sans reload)
-	@$(MAKE) clean
-	@poetry run python -m uvicorn main:app --host 0.0.0.0 --port 8000
-
-
</code_context>
<issue_to_address>
**Documented server commands do nothing**

When an operator follows either documented command, `make st` and `make restart` are still advertised in `GEMINI.md` and `doc/cli/commands/health.md`, but their recipes are removed while the goals remain phony, so Make exits successfully without starting or restarting the server.

Update the documentation to use supported commands, or restore the removed Make targets.

Also at `makefile:248-252`.
</issue_to_address>

### Comment 7
<location path="makefile" line_range="64-66" />
<code_context>
 # ============================================================
 lint-check: ## Vérifier le style sans modifier (CI)
-	@poetry run black xcore/ --check
+	@poetry run black xcore/ --check 2>/dev/null || true
 	@poetry run isort xcore/ --check-only
-	@poetry run flake8 xcore/
+	@poetry run flake8 xcore/ || { echo "⚠️  flake8 warnings (non-fatales en CI)"; exit 0; }

 lint-fix: ## Corriger automatiquement le style de xcore/ (black → isort → flake8 check)
</code_context>
<issue_to_address>
**Lint targets ignore style failures**

When black or Flake8 reports an error, `lint-check` and `ci-lint` suppress Black and Flake8 failures, so these targets return success even when formatting or lint checks fail; callers relying on them receive a false passing result.

Propagate the Black and Flake8 exit codes, or make these targets explicitly warning-only and provide a separate enforcing lint target.

Also at `makefile:121-123`.
</issue_to_address>

### Comment 8
<location path="xcore/sdk/decorators.py" line_range="75" />
<code_context>
+    Utilisable seul (sur n'importe quelle méthode) ou empilé avec @action — dans
+    ce dernier cas l'ordre n'importe pas, les deux décorateurs posent des
+    attributs distincts (_xcore_schema / _xcore_action) sur la même fonction.
+    @action accepte aussi directement ces mêmes paramètres pour l'usage fusionné.
+
     Le format du dict `input` suit la convention pydantic create_model :
</code_context>
<issue_to_address>
**Documented decorator usage raises TypeError**

When a plugin author follows the `@schema` docstring and passes schema parameters directly to `@action`, `action()` accepts only `name` and `permissions`, so passing documented schema arguments such as `version=` raises `TypeError` while importing the plugin.

Make `action()` accept and apply the documented schema parameters, or revise the docstring to describe a supported usage.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 8 findings to address first, and a token can be decoded into, or an already-supplied principal can be propagated as, the caller identity exposed to plugin code; if that identity is wrong, downstream authorization or business actions may run for the wrong user. Reverting restores the previous behavior but cannot undo any data access or other side effects that occurred while the incorrect principal was in use.

Blocking findings: xcore/kernel/api/auth.py:78, xcore/kernel/runtime/supervisor.py:348, makefile:129, xcore/kernel/api/auth.py:94, xcore/kernel/runtime/supervisor.py:348, and 3 more


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread xcore/kernel/api/auth.py
Principal (sub/roles/permissions) résolu pour l'appel IPC en cours via
l'AuthBackend enregistré — None si aucun token n'a été transmis ou résolu.
"""
return _current_principal.get()

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.

🟡 Medium · Nested plugins trust altered identity

When plugin code mutates the current principal before making a nested call, get_current_principal() exposes a mutable AuthPayload, and TrustedBase.call_plugin() forwards the same object. Mutations alter the current identity and reach downstream plugins, allowing forged roles or permissions and cross-call interference.

Make principals immutable or return and forward defensive deep copies at both boundaries.

Also at xcore/kernel/api/contract.py:171, xcore/kernel/runtime/supervisor.py:348.

Prompt for AI agents
In `xcore/kernel/api/auth.py` at line 78:

**Nested plugins trust altered identity**

When plugin code mutates the current principal before making a nested call, `get_current_principal()` exposes a mutable `AuthPayload`, and `TrustedBase.call_plugin()` forwards the same object. Mutations alter the current identity and reach downstream plugins, allowing forged roles or permissions and cross-call interference.

Make principals immutable or return and forward defensive deep copies at both boundaries.

Also at `xcore/kernel/api/contract.py:171`, `xcore/kernel/runtime/supervisor.py:348`.

# Même pattern que le ContextVar tenant : posé une fois ici pour l'appel
# en cours, lu par get_current_principal() dans le plugin — jamais de
# mutation d'un objet PluginContext partagé entre requêtes concurrentes.
principal_token = _current_principal.set(principal)

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.

🟡 Medium · Background tasks retain caller identity

When a handler starts a detached task during an authenticated IPC call and that task later makes a nested plugin call, _dispatch() resets _current_principal only in its own task context; the detached task keeps its inherited copy. TrustedBase.call_plugin() then forwards that stale principal, so the downstream plugin sees the original user after the request ends.

Prevent detached tasks from retaining or forwarding the request principal after _dispatch() completes.

Also at xcore/kernel/api/contract.py:171.

Prompt for AI agents
In `xcore/kernel/runtime/supervisor.py` at line 348:

**Background tasks retain caller identity**

When a handler starts a detached task during an authenticated IPC call and that task later makes a nested plugin call, `_dispatch()` resets `_current_principal` only in its own task context; the detached task keeps its inherited copy. `TrustedBase.call_plugin()` then forwards that stale principal, so the downstream plugin sees the original user after the request ends.

Prevent detached tasks from retaining or forwarding the request principal after `_dispatch()` completes.

Also at `xcore/kernel/api/contract.py:171`.

Comment thread makefile
Comment on lines -122 to -129
security-check: ## Vérifications rapides (.env, mots de passe en dur)
@if git ls-files | grep -q "\.env$$"; then \
echo "❌ .env est tracké par git !"; exit 1; \
else echo "✅ .env correctement ignoré"; fi
@if grep -rn "password\s*=\s*[\"'][^\"']*[\"']" xcore/ 2>/dev/null; then \
echo "❌ Mots de passe potentiels détectés !"; \
else echo "✅ Aucun mot de passe en dur"; fi

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.

🟡 Medium · CI security check becomes a no-op

When the CI security job or ci-security target runs, ci-security and the GitHub security job still invoke make security-check, but the target's recipe is removed while security-check remains in .PHONY; Make therefore succeeds without checking whether .env is tracked or passwords are hard-coded.

Restore the security-check recipe or remove its callers and replace the checks with an equivalent active target.

Prompt for AI agents
In `makefile` at lines 122-129:

**CI security check becomes a no-op**

When the CI security job or `ci-security` target runs, `ci-security` and the GitHub security job still invoke `make security-check`, but the target's recipe is removed while `security-check` remains in `.PHONY`; Make therefore succeeds without checking whether `.env` is tracked or passwords are hard-coded.

Restore the `security-check` recipe or remove its callers and replace the checks with an equivalent active target.

Comment thread xcore/kernel/api/auth.py
Comment on lines +92 to +94
token = await backend.extract_token(request)
if token is None:
return 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.

🟠 High · Backend errors abort anonymous calls

When the registered backend raises while extracting or decoding a request token, resolve_principal_from_request() lets the backend exception escape, so the generic HTTP endpoint never reaches supervisor.call() and returns an error instead of dispatching anonymously.

Catch extraction and decoding errors in the resolver and return None so the call proceeds without a principal.

Also at xcore/kernel/api/router.py:168.

Prompt for AI agents
In `xcore/kernel/api/auth.py` at lines 92-94:

**Backend errors abort anonymous calls**

When the registered backend raises while extracting or decoding a request token, `resolve_principal_from_request()` lets the backend exception escape, so the generic HTTP endpoint never reaches `supervisor.call()` and returns an error instead of dispatching anonymously.

Catch extraction and decoding errors in the resolver and return `None` so the call proceeds without a principal.

Also at `xcore/kernel/api/router.py:168`.

# Même pattern que le ContextVar tenant : posé une fois ici pour l'appel
# en cours, lu par get_current_principal() dans le plugin — jamais de
# mutation d'un objet PluginContext partagé entre requêtes concurrentes.
principal_token = _current_principal.set(principal)

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.

🟡 Medium · Sandboxed plugins lose caller identity

When an authenticated call targets a sandboxed plugin, PluginSupervisor._dispatch() sets _current_principal in the supervisor process, but the sandbox worker receives only the action and payload. Its get_current_principal() therefore returns None, so sandboxed plugin code cannot access the caller identity.

Propagate the principal to the sandbox worker and set it in the worker’s context for the call.

Prompt for AI agents
In `xcore/kernel/runtime/supervisor.py` at line 348:

**Sandboxed plugins lose caller identity**

When an authenticated call targets a sandboxed plugin, `PluginSupervisor._dispatch()` sets `_current_principal` in the supervisor process, but the sandbox worker receives only the action and payload. Its `get_current_principal()` therefore returns `None`, so sandboxed plugin code cannot access the caller identity.

Propagate the principal to the sandbox worker and set it in the worker’s context for the call.

Comment thread makefile
Comment on lines -50 to -52
st: ## Lancer en mode production (sans reload)
@$(MAKE) clean
@poetry run python -m uvicorn main:app --host 0.0.0.0 --port 8000

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.

🟡 Medium · Documented server commands do nothing

When an operator follows either documented command, make st and make restart are still advertised in GEMINI.md and doc/cli/commands/health.md, but their recipes are removed while the goals remain phony, so Make exits successfully without starting or restarting the server.

Update the documentation to use supported commands, or restore the removed Make targets.

Also at makefile:248-252.

Prompt for AI agents
In `makefile` at lines 50-52:

**Documented server commands do nothing**

When an operator follows either documented command, `make st` and `make restart` are still advertised in `GEMINI.md` and `doc/cli/commands/health.md`, but their recipes are removed while the goals remain phony, so Make exits successfully without starting or restarting the server.

Update the documentation to use supported commands, or restore the removed Make targets.

Also at `makefile:248-252`.

Comment thread makefile
Comment on lines +64 to +66
@poetry run black xcore/ --check 2>/dev/null || true
@poetry run isort xcore/ --check-only
@poetry run flake8 xcore/
@poetry run flake8 xcore/ || { echo "⚠️ flake8 warnings (non-fatales en CI)"; exit 0; }

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.

🟡 Medium · Lint targets ignore style failures

When black or Flake8 reports an error, lint-check and ci-lint suppress Black and Flake8 failures, so these targets return success even when formatting or lint checks fail; callers relying on them receive a false passing result.

Propagate the Black and Flake8 exit codes, or make these targets explicitly warning-only and provide a separate enforcing lint target.

Also at makefile:121-123.

Prompt for AI agents
In `makefile` at lines 64-66:

**Lint targets ignore style failures**

When black or Flake8 reports an error, `lint-check` and `ci-lint` suppress Black and Flake8 failures, so these targets return success even when formatting or lint checks fail; callers relying on them receive a false passing result.

Propagate the Black and Flake8 exit codes, or make these targets explicitly warning-only and provide a separate enforcing lint target.

Also at `makefile:121-123`.

Comment thread xcore/sdk/decorators.py
Utilisable seul (sur n'importe quelle méthode) ou empilé avec @action — dans
ce dernier cas l'ordre n'importe pas, les deux décorateurs posent des
attributs distincts (_xcore_schema / _xcore_action) sur la même fonction.
@action accepte aussi directement ces mêmes paramètres pour l'usage fusionné.

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.

🟡 Medium · Documented decorator usage raises TypeError

When a plugin author follows the @schema docstring and passes schema parameters directly to @action, action() accepts only name and permissions, so passing documented schema arguments such as version= raises TypeError while importing the plugin.

Make action() accept and apply the documented schema parameters, or revise the docstring to describe a supported usage.

Prompt for AI agents
In `xcore/sdk/decorators.py` at line 75:

**Documented decorator usage raises TypeError**

When a plugin author follows the `@schema` docstring and passes schema parameters directly to `@action`, `action()` accepts only `name` and `permissions`, so passing documented schema arguments such as `version=` raises `TypeError` while importing the plugin.

Make `action()` accept and apply the documented schema parameters, or revise the docstring to describe a supported usage.

@traoreera
traoreera merged commit f8f2514 into main Oct 6, 2026
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

config core dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant