Skip to main content

Session-Scoped Network Rules Plan

Problem

Greywall profiles manage credentials and filesystem rules, but not network rules. Network rules live in greyproxy's SQLite DB as global permanent/temporary entries. When a user runs greywall --profile codex, they must manually approve every network destination through the dashboard. This is the #1 friction point from user feedback.

Solution Overview

  1. greyproxy: Accept network rules as part of session creation, scope them to session lifetime, auto-cleanup on session end/expire.
  2. greywall: Add network rule presets to profiles, send them with session creation, refine --learning to extend defaults.

Current Flow (broken)

greywall --profile codex
-> POST /api/sessions (credentials only)
-> codex tries api.openai.com -> no rule -> pending -> user clicks allow
-> repeat for every domain, every session

Proposed Flow

greywall --profile codex
-> POST /api/sessions (credentials + network rules from profile)
-> codex tries api.openai.com -> session rule matches -> allowed instantly
-> session ends -> session-scoped rules auto-deleted

greyproxy Changes

1. DB Migration

Add session_id column to rules table:

ALTER TABLE rules ADD COLUMN session_id TEXT DEFAULT NULL;
CREATE INDEX idx_rules_session_id ON rules(session_id);

Add allow_all column to sessions table:

ALTER TABLE sessions ADD COLUMN allow_all INTEGER DEFAULT 0;

Seed built-in localhost rules:

INSERT INTO rules (container_pattern, destination_pattern, port_pattern, rule_type, action, created_by)
VALUES ('*', '127.0.0.1', '*', 'builtin', 'allow', 'builtin');
INSERT INTO rules (container_pattern, destination_pattern, port_pattern, rule_type, action, created_by)
VALUES ('*', '::1', '*', 'builtin', 'allow', 'builtin');
INSERT INTO rules (container_pattern, destination_pattern, port_pattern, rule_type, action, created_by)
VALUES ('*', 'localhost', '*', 'builtin', 'allow', 'builtin');

2. API Change: POST /api/sessions

Add optional network_rules and allow_all fields:

{
"session_id": "uuid",
"container_name": "codex",
"mappings": { ... },
"network_rules": [
{ "destination_pattern": "api.openai.com", "port_pattern": "443", "action": "allow" },
{ "destination_pattern": "**.openai.com", "port_pattern": "443", "action": "allow" }
],
"allow_all": false,
"ttl_seconds": 900
}

Response adds rules_created count.

3. Layered Rule Resolution

Rules have three source layers, evaluated in priority order:

PrioritySourceHow identified
1 (highest)Globalsession_id IS NULL AND created_by != 'builtin'
2Sessionsession_id IS NOT NULL
3 (lowest)Built-increated_by = 'builtin'

Resolution: highest layer match wins. Within same layer, highest specificity wins. Deny beats allow at same specificity within same layer.

This means:

  • Global deny always blocks, even if profile says allow (strict mode)
  • Global allow always permits, even if profile doesn't include it
  • Session rules fill the gap for common tool destinations
  • Built-in localhost rules are lowest priority, overridable by session or global deny

4. Per-Container AllowAll

When a session has allow_all = true, greyproxy skips ACL evaluation for that container. Used by --learning mode. Only affects the specific container, not global traffic.

5. Session Rule Lifecycle

EventEffect on session rules
Session createdRules inserted with session_id, expires_at from session TTL
Session heartbeatRules' expires_at extended to match new session expiry
Session deletedRules deleted
Session expiredBackground cleanup deletes rules alongside session
Session upsertedOld session rules deleted, new ones inserted

greywall Changes

1. Config Extension

Add NetworkRule type and Rules field to NetworkConfig:

type NetworkRule struct {
Destination string `json:"destination"`
Port string `json:"port,omitempty"` // default "*"
Action string `json:"action,omitempty"` // default "allow"
Notes string `json:"notes,omitempty"`
}

type NetworkConfig struct {
// ... existing fields
Rules []NetworkRule `json:"rules,omitempty"`
}

2. Agent Profile Defaults

Each agent profile gets network rules for its known API endpoints:

ProfileDefault allow destinations
claudeapi.anthropic.com:443, **.anthropic.com:443, github.com:443, *.githubusercontent.com:443
codexapi.openai.com:443, **.openai.com:443
opencodeapi.openai.com:443, api.anthropic.com:443
aiderapi.openai.com:443, api.anthropic.com:443
cursorapi2.cursor.sh:443, api.openai.com:443, api.anthropic.com:443
geminigenerativelanguage.googleapis.com:443
gooseapi.openai.com:443, api.anthropic.com:443
ampapi.anthropic.com:443, api.openai.com:443
copilotapi.github.com:443, copilot-proxy.githubusercontent.com:443
clineapi.anthropic.com:443, api.openai.com:443
Othersapi.openai.com:443, api.anthropic.com:443 (safe default)

3. Session Creation with Network Rules

RegisterSession() sends merged network rules (profile defaults + user overrides + CLI flags) as network_rules in the session request.

New CLI flag: --allow PATTERN adds a one-off allow rule for the session.

4. Learning Mode Refinement

--learning (existing flag):

  • Loads default profile for the tool
  • Sends profile network rules to greyproxy
  • Sets allow_all: true on the session (everything goes through)
  • On session end: queries logs, filters out known profile destinations, shows new ones
  • Offers to save discovered destinations to user profile

--learning --blank (new flag):

  • Skips default profile network rules
  • Sets allow_all: true only
  • Shows ALL destinations in summary (for auditing or untrusted defaults)

5. Post-Learning Output

[greywall] Learning session complete for "codex"

Default profile rules (3 rules, already known):
ok api.openai.com:443
ok **.openai.com:443
ok 127.0.0.1:*

New destinations discovered (2):
+ sentry.io:443 (4 requests)
+ registry.npmjs.org:443 (17 requests)

Add to profile? [Y/n] y
Saved to ~/.config/greywall/learned/codex.json

Implementation Phases

Phase 1: greyproxy (this repo)

  1. Migration: session_id on rules, allow_all on sessions, built-in localhost rules
  2. Extend SessionCreateInput with NetworkRules and AllowAll
  3. Session rule CRUD (create/delete/heartbeat-extend)
  4. Layered FindMatchingRule resolution
  5. Per-container allow_all check
  6. API handler updates
  7. Tests

Phase 2: greywall (separate repo)

  1. NetworkRule type in config
  2. Network rules in agent profiles
  3. Send network_rules in RegisterSession
  4. --allow CLI flag
  5. --blank flag for learning
  6. Post-learning log query and profile save