Spaces:
Sleeping
Sleeping
| title: Privilege Desk | |
| emoji: π’ | |
| colorFrom: blue | |
| colorTo: indigo | |
| sdk: docker | |
| pinned: false | |
| app_port: 8000 | |
| base_path: /web | |
| # PrivilegeDesk | |
| **Zero-Standing-Privilege Ops Environment for Training AI Agents** | |
| A simulated enterprise access-control environment built on [OpenEnv](https://github.com/meta-pytorch/OpenEnv). | |
| An AI agent is dropped into a synthetic corporate IAM system and must handle real-world privilege management tasks β from reviewing a single access request to conducting a full entitlement audit. | |
| --- | |
| ## Environment Overview | |
| | Property | Value | | |
| |----------|-------| | |
| | **Domain** | Identity & Access Management (IAM) | | |
| | **Tasks** | 3 (easy β medium β hard) | | |
| | **Tools** | 19 structured tool calls | | |
| | **Reward** | Partial credit, 0.0β1.0, deterministic grading | | |
| | **Generation** | Fully procedural β unique episode per seed | | |
| | **API** | OpenEnv-compliant (reset / step / state / grader / tasks / baseline) | | |
| --- | |
| ## The 3 Tasks | |
| ### Task 1 β Access Decision (`access_decision`) Β· Easy | |
| > "A new access request has arrived. Review the request, inspect the applicable policy, and decide whether to approve or deny it. If approving, select the correct role and TTL." | |
| - **Steps**: 1β5 | |
| - **Grading**: correct decision (40%) + correct role (25%) + correct TTL (20%) + justification category (15%) | |
| - **Baseline difficulty**: ~0.7β0.9 with a well-prompted LLM | |
| ### Task 2 β JIT Escalation (`jit_escalation`) Β· Medium | |
| > "Process an urgent just-in-time privilege escalation: find the correct approval chain, route the request in order, attach the incident ticket, set the TTL, and activate the grant." | |
| - **Steps**: 3β15 | |
| - **Grading**: correct approvers (20%) + routing order (15%) + ticket attached (15%) + role (15%) + TTL (15%) + final decision (20%) | |
| - **Baseline difficulty**: ~0.4β0.6 with a well-prompted LLM | |
| ### Task 3 β Access Review (`access_review`) Β· Hard | |
| > "Conduct an access review for a user. Identify risky, stale, or over-privileged entitlements and revoke the minimum set β without breaking active workflows." | |
| - **Steps**: 5β25 | |
| - **Grading**: precision (30%) + recall (30%) + workflow preservation (20%) + policy compliance (10%) + submission (10%) | |
| - **Baseline difficulty**: ~0.2β0.4 with a well-prompted LLM | |
| --- | |
| ## The World Model | |
| Each episode procedurally generates a complete synthetic enterprise from a seed: | |
| | Entity | Description | | |
| |--------|-------------| | |
| | **Users** | Employees with name, email, department, manager | | |
| | **Resources** | Databases, repos, cloud projects, admin consoles | | |
| | **Policies** | Rules: max role + max TTL + required approvers per resource | | |
| | **Entitlements** | Current userβroleβresource assignments | | |
| | **Groups** | Team groups for inherited permissions (Task 3) | | |
| | **Approval Chains** | Ordered approver lists per request (Task 2) | | |
| | **Workflows** | Active pipelines that depend on entitlements (Task 3) | | |
| | **Audit DB** | Historical access events queryable via `audit.query` | | |
| | **Hidden State** | Ground truth β generated at reset, used by grader | | |
| --- | |
| ## API Reference | |
| ### Standard OpenEnv Endpoints | |
| | Endpoint | Method | Description | | |
| |----------|--------|-------------| | |
| | `/reset` | POST | Start a new episode. Pass `task_id` and optional `seed`. | | |
| | `/step` | POST | Execute a tool call. Returns observation + reward + done. | | |
| | `/state` | GET | Current episode metadata (episode_id, step_count). | | |
| | `/schema` | GET | JSON schemas for Action and Observation. | | |
| | `/health` | GET | Health check. | | |
| ### Hackathon-Required Endpoints | |
| | Endpoint | Method | Description | | |
| |----------|--------|-------------| | |
| | `/tasks` | GET | Lists all 3 tasks with schemas and grading weights. | | |
| | `/grader` | POST | Returns 0.0β1.0 episode score with full breakdown. | | |
| | `/baseline` | POST | Runs naive baseline agent on all 3 tasks. | | |
| ### Reset Parameters | |
| ```json | |
| { | |
| "task_id": "access_decision", // "access_decision" | "jit_escalation" | "access_review" | |
| "seed": 42, // optional β omit for random episode | |
| "difficulty_level": 1 // 1-3 (scales entity counts) | |
| } | |
| ``` | |
| ### Step Action Format | |
| ```json | |
| { | |
| "action": { | |
| "tool_name": "access.decide", | |
| "arguments": { | |
| "request_id": "req_000", | |
| "decision": "approve", | |
| "role": "viewer", | |
| "ttl_hours": 4, | |
| "justification_category": "operational" | |
| } | |
| } | |
| } | |
| ``` | |
| --- | |
| ## Available Tools (19 total) | |
| | Tool | Arguments | Used In | | |
| |------|-----------|---------| | |
| | `policy.lookup` | `resource_id` | T1, T2 | | |
| | `policy.list` | β | T1, T2, T3 | | |
| | `org.get_user` | `user_id` | T1, T2, T3 | | |
| | `org.get_manager` | `user_id` | T2 | | |
| | `org.list_users` | `department?` | T2, T3 | | |
| | `request.view` | `request_id?` | T1, T2 | | |
| | `request.list` | β | T2 | | |
| | `approval.route` | `request_id`, `approver_id` | T2 | | |
| | `approval.check_status` | `request_id` | T2 | | |
| | `access.decide` | `request_id`, `decision`, `role`, `ttl_hours`, `justification_category?` | T1 | | |
| | `access.grant` | `request_id` | T2 | | |
| | `access.set_ttl` | `request_id`, `ttl_hours` | T2 | | |
| | `entitlement.list` | `user_id?` | T1, T3 | | |
| | `entitlement.inspect` | `entitlement_id` | T3 | | |
| | `entitlement.revoke` | `entitlement_id`, `reason?` | T3 | | |
| | `audit.query` | `user_id?`, `resource_id?`, `days?` | T3 | | |
| | `group.resolve` | `group_id?` or `user_id?` | T3 | | |
| | `workflow.check_active` | `user_id?`, `entitlement_id?` | T3 | | |
| | `review.submit` | `summary?` | T3 | | |
| --- | |
| ## Reward Design | |
| ### Per-Step Rewards (returned on every `/step`) | |
| - `+0.02β0.05` for discovering new information (policies, entitlements, audit logs) | |
| - `+0.05β0.08` for correctly identifying or revoking a risky entitlement | |
| - `-0.02` for tool errors | |
| - `-0.01` for redundant (repeated) tool calls | |
| - `-0.03` for routing to the wrong approver | |
| - `-0.10` for revoking a workflow-critical entitlement | |
| ### Episode Score (returned when `done=True`, accessible via `/grader`) | |
| All task graders return a weighted 0.0β1.0 score with **partial credit**. Binary 0/1 is never used β every field is independently gradable. | |
| --- | |
| ## Local Development | |
| ```bash | |
| # Install dependencies | |
| cd privilege_desk | |
| uv sync | |
| # Run server (hot-reload) | |
| uv run server | |
| # OR | |
| uvicorn server.app:app --host 0.0.0.0 --port 8000 --reload | |
| # Test episode generation | |
| uv run python -c " | |
| import sys; sys.path.insert(0, '.') | |
| from pipeline.episode_generator import generate_episode | |
| ws = generate_episode(task_id='access_decision', seed=42) | |
| print('Users:', len(ws['users']), 'Policies:', len(ws['policies'])) | |
| " | |
| # Run baseline inference (requires API key) | |
| export API_BASE_URL=https://router.huggingface.co/v1 | |
| export HF_TOKEN=hf_... | |
| export MODEL_NAME=meta-llama/Llama-3.3-70B-Instruct | |
| uv run python inference.py | |
| # Validate submission | |
| openenv validate | |
| ``` | |
| ## Docker | |
| ```bash | |
| # Build | |
| docker build -t privilege-desk:latest -f server/Dockerfile . | |
| # Run | |
| docker run -p 8000:8000 privilege-desk:latest | |
| # Health check | |
| curl http://localhost:8000/health | |
| ``` | |
| --- | |
| ## Architecture | |
| ``` | |
| privilege_desk/ | |
| βββ models.py # Pydantic Action + Observation | |
| βββ pipeline/ | |
| β βββ episode_generator.py # Procedural world generation | |
| β βββ task_templates.py # 3 task definitions | |
| βββ env/ | |
| β βββ world_state.py # Episode lifecycle (reset/step/grade) | |
| β βββ action_router.py # Tool dispatch + audit log | |
| β βββ tools.py # All 19 tool implementations | |
| βββ reward/ | |
| β βββ grader.py # Per-task graders (0.0β1.0) | |
| β βββ aggregator.py # Step reward + episode score | |
| βββ server/ | |
| β βββ app.py # FastAPI app (standard + custom endpoints) | |
| β βββ privilege_desk_environment.py # OpenEnv Environment subclass | |
| βββ inference.py # Baseline LLM agent | |
| βββ openenv.yaml # OpenEnv spec declaration | |
| βββ Dockerfile # HF Spaces deployment | |
| ``` | |
| --- | |
| ## Grading Details | |
| ### Task 1: Access Decision | |
| | Component | Weight | What's Checked | | |
| |-----------|--------|----------------| | |
| | Correct approve/deny | 40% | Matches policy: requested role β€ max_role | | |
| | Correct role | 25% | Exact match to policy max_role (partial credit for lower roles) | | |
| | Correct TTL | 20% | Within Β±2h of policy max_ttl | | |
| | Justification category | 15% | Correct category label | | |
| ### Task 2: JIT Escalation | |
| | Component | Weight | What's Checked | | |
| |-----------|--------|----------------| | |
| | Correct approvers | 20% | Set of routed approver IDs matches required chain | | |
| | Routing order | 15% | Sequential order matches policy chain | | |
| | Ticket attached | 15% | Non-empty ticket_id in request | | |
| | Correct role | 15% | Requested role β€ policy max_role | | |
| | Correct TTL | 15% | Within Β±2h of policy max_ttl | | |
| | Final grant/deny | 20% | Correctly activated or denied | | |
| ### Task 3: Access Review | |
| | Component | Weight | What's Checked | | |
| |-----------|--------|----------------| | |
| | Precision | 30% | Revoked entitlements that were genuinely risky | | |
| | Recall | 30% | Risky entitlements that were caught | | |
| | Workflow preservation | 20% | No active workflows broken | | |
| | Policy compliance | 10% | Remaining entitlements pass policy check | | |
| | Submission | 10% | `review.submit` was called | | |
| --- | |
| ## License | |
| BSD-style β see LICENSE file. | |