feat(policy-engine): update the demo for PPE 0.2.0 - #17
Merged
Conversation
0.1.1 is unreleased, and cargo honours [patch] only in the workspace root it builds, so praxis patching the engine to a sibling path does nothing from here and the gateway has to name those crates itself. Not a second thing to point at: praxis reads the engine as ../praxis-policy, so .policy follows the same relative path from whatever .praxis resolves to. PPE_DIR overrides and a clone is the fallback. Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Every engine crate, not only the facade: praxis depends on the facade and the facade on the rest, so leaving one unpatched resolves it from crates.io at 0.1.0 and the graph gets two copies. For praxis-policy-core that means two PluginFactory traits and the host registration in main.rs stops typechecking. cargo tree --duplicates reports none. The two reference plugins move to the checkout for the same reason; they are workspace members there and resolve the core by path. Two fixes the port surfaced, both unrelated to the engine: praxis-ai at 333f93d predates praxis a6ea13f4, which converted &Option<T> to Option<&T> across crates, so its MCP and A2A filters no longer compile. Bumped to ai main. That revision then needs praxis's admin-api feature: it calls the admin-endpoint helpers unconditionally while praxis gates them and praxis-ai declares its praxis dependencies with no features. Turned on the way policy-engine already is. Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
engine_settings replaces plugin_settings, dispatch: policy replaces routing_enabled, and each route's flat pre_invocation nests under authorization. A declared priority is a load error under policy dispatch, and the audit logger's ordering comment went with the key: order is now the order the document writes the steps. The five plugins that reach Keycloak declare perform_http. The engine performs no outbound HTTP of its own since 0.1.1, so without it a jwks_url issuer, a token exchange and a CIBA dispatch fail at initialize(). audit-log declares one hook rather than three: this demo has only tool routes, so the other two were uncovered and the load reported it. Two comments in the CEL and OPA variants described a wrapped APL form that no document can write now. The praxis*.yaml listeners opt into allow_private_endpoints. Every backend here is on localhost and praxis refuses those unless a config says so. All three load clean and raise no alarms. Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
The engine is unreleased too, so the gateway patches its crates to gateway/.policy alongside praxis at gateway/.praxis. Records why the entries cannot be inherited from praxis, why every engine crate is listed, and that .policy is derived from .praxis rather than asked for separately. Also drops an apl: wrapper mention from the file table; no document can write one now. Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Every other scenario shows the gateway deciding. This is the only channel that carries a decision onward: global.assertions.request: renders engine-derived identity into headers hr-mcp reads. Four entries, one per shape the feature has: a slot, a claim, a collection with the encode: it must declare, and a members object. strip: withholds Bob's raw JWT, which delegate() already replaced on authorization, so the upstream ends up holding no credential he issued. Scenario 12 shows both halves, the second being the point: Bob sends x-auth-user-id: root and the upstream still sees his real subject id, because an entry removes its target before injecting. hr-mcp logs the asserted names so the effect is visible. The headers are unsigned and the README says so first: hr-mcp believes them because it believes the network path, not because it can verify anything. Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
The engine refuses loopback egress by default as of the security fixes on main, so every scenario failed at the identity gate with auth.jwks_unavailable. Keycloak runs on localhost:8081 here. Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
The engine's egress resolver added it. Comes through the local path dep. Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Only praxis-policy-core and praxis-policy-orchestration stay on the local checkout. The reference plugins are unpublished and reach those two by path, so patching them keeps the graph to one copy of each. The other eleven engine crates come from the registry. Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
The probe sent HTTP/1.0 with no Host, and Keycloak answers 500 there: it throws building the realm's base URL from a null authority. So the container never reported healthy and logged an NPE every 5s. Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
The auto-approve step took the first pending entry from the auth-channel, which is the oldest. A run abandoning one, such as a manual run that timed out, left it there for the next run to approve instead of its own, which then polled a still-pending request until it gave up. Record the pending ids before the call and take one that was not there. Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
praxis main requires pingora-core 0.8.4, and the gateway lock pinned the fork at 0.8.2, so the graph no longer resolved. Updating it left the fork's lru crate wired to arrayvec 0.5, which does not compile against 0.8.4, so that package is re-resolved too. Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
The gateway pins praxis by path, and praxis moved core, filter, protocol and tls under `crates/`, so all eight `[patch]` entries stopped resolving. `DEFAULT_PRAXIS_REF` stays where it is: it clones from praxis upstream, and no upstream commit yet carries both that move and the PPE 0.2.0 port. Recorded on the ref instead, since the demo needs `.praxis` pointing at a checkout that has the port either way. Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
The PPE 0.2.0 port is on praxis main, so the pinned ref moves to that commit and the demo no longer needs a local praxis checkout. Verified from a fresh clone of both upstreams: 12/12 scenarios on Cedar, CEL and OPA. Two claims that stopped being true are corrected here too. The engine release is published; what is unpublished is its two reference plugins, which is why `.policy` is still needed. And praxis reads the engine from crates.io rather than `../praxis-policy`, so the sibling lookup is a convenience for working on both at once, not a constraint. Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
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.
Updates the policy-engine demo to PPE 0.2.0.
The engine now comes from crates.io. The gateway still builds Praxis with the
policy-enginefilter and the two unpublished reference plugins from source.Adds scenario 12 for the
assertions:block. The gateway derives four identity headers from the verified token, and hr-mcp logs what it receives. When Bob repeats the call with a spoofedx-auth-user-id: rootheader, the upstream still receives his real subject ID.Other changes:
crates/directory.Builds from praxis
mainat a pinned commit.Verified from a fresh clone of both upstreams: 12/12 scenarios on Cedar, CEL and OPA, no alarms.