Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .ai/knowledge/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Concept pages explain cross-module ideas. Read `concepts/README.md` before creat
| Query, Router, RouteQuery, RouteNotFound, Reject, Accept, Session, Preprocessor, Gateway, routing pipeline | `concepts/query.md` |
| Auth, Authorize, Action, ActionSudo, ActionRelayFor, auth handler, authorization | `concepts/auth.md` |
| lib/astrald, lib/apphost, lib/routing, lib/apps, lib/ipc, lib/query, astrald.Default, OpRouter, IncomingQuery, Serve, AppRegistrar, client library | `concepts/lib.md` |
| Object, ObjectID, Repository, Receiver, Describer, Searcher, Finder, Holder, objects.Load, objects.Save, repo group | `concepts/objects.md` |
| Object, ObjectID, Repository, Receiver, Describer, Searcher, Finder, Holder, objects.Load, objects.Save, objects.purge, object holds, repo group | `concepts/objects.md` |
| Op, operation, op_*.go, OpName, args struct, ops.Set, method name, query method string | `concepts/operations.md` |
| Node, module lifecycle, Load Inject LoadDependencies Prepare Run, Scheduler, core.Inject, core.Node | `concepts/node.md` |
| Transport, exonet, Stream, Link, link strategy, TCP, KCP, Tor, layer stack | `concepts/transport.md` |
Expand All @@ -42,16 +42,16 @@ Read the module guide when entering that module's source.
| Module path / keywords | Read |
|---|---|
| `mod/nodes/`, Link, Stream, Session, peer, flow control, frame protocol, migration, link establishment | `modules/nodes.md` |
| `mod/apphost/`, token, handler registration, IPC bridge, guest connection, contract indexing | `modules/apphost.md` |
| `mod/objects/`, Load[T], Save, Commit, Discard, Blueprint, repo group, Push, object store | `modules/objects.md` |
| `mod/apphost/`, token, handler registration, IPC bridge, guest connection, contract indexing, app-owned object holds | `modules/apphost.md` |
| `mod/objects/`, Load[T], Save, Commit, Discard, Blueprint, repo group, Push, object store, purge, Holder | `modules/objects.md` |
| `mod/dir/`, alias, filter, resolve, DisplayName, ApplyFilters, IdentityFilter, identity resolver | `modules/dir.md` |
| `mod/auth/`, Authorize, Add, auth handler | `modules/auth.md` |
| `mod/auth/`, Authorize, Add, auth handler, active contract object holder | `modules/auth.md` |
| `mod/gateway/`, relay socket, binder, connector, gateway relay | `modules/gateway.md` |
| `mod/nat/`, hole punch, ConePuncher, UDP traversal, nat.Hole | `modules/nat.md` |
| `mod/kcp/`, KCP, UDP transport, local-port mapping, ephemeral listener | `modules/kcp.md` |
| `mod/tcp/`, TCP listener, ListenPort, CreateEphemeralListener | `modules/tcp.md` |
| `mod/exonet/`, Dialer, Unpacker, Parser, SetDialer, network name, transport registry | `modules/exonet.md` |
| `mod/user/`, user identity, Swarm member, MaintainLinkTask, node contract | `modules/user.md` |
| `mod/user/`, user identity, Swarm member, MaintainLinkTask, node contract, asset object holder | `modules/user.md` |
| `mod/nearby/`, local discovery, broadcast, Stealth, Visible, UDP discovery | `modules/nearby.md` |
| `mod/scheduler/`, schedule task, run task, PoolLocker, Releaser, FuncAdapter | `modules/scheduler.md` |
| `mod/events/`, event, subscribe, emit, EventReceiver, EventEmitter | `modules/events.md` |
Expand All @@ -60,7 +60,7 @@ Read the module guide when entering that module's source.
| `mod/services/`, service registry, named service, bind service, AddService | `modules/services.md` |
| `mod/shell/`, shell command, terminal, admin CLI, command handler | `modules/shell.md` |
| `mod/tree/`, config tree, persistent setting, tree.Value, Follow, tree path | `modules/tree.md` |
| `mod/crypto/`, sign, verify, Engine, PrivateKey, SignableObject, secp256k1, BIP137 | `modules/crypto.md` |
| `mod/crypto/`, sign, verify, Engine, PrivateKey, SignableObject, secp256k1, BIP137, private-key object holder | `modules/crypto.md` |
| `mod/ip/`, LocalIPs, PublicIPCandidates, DefaultGateway, EventNetworkAddressChanged | `modules/ip.md` |
| `mod/tor/`, Tor, onion, hidden service, SOCKS5, ED25519-V3 | `modules/tor.md` |
| `mod/fwd/`, port forward, bridge, AstralServer, TCPServer, TorTarget | `modules/fwd.md` |
Expand Down
14 changes: 13 additions & 1 deletion .ai/knowledge/concepts/objects.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,16 @@ automatically through type assertions.
| `Describer` | metadata request for an ObjectID |
| `Searcher` | text/tag search over module-owned indexes |
| `Finder` | provider lookup by ObjectID |
| `Holder` | storage policy and eviction decisions |
| `Holder` | cleanup/purge policy; held objects are skipped by cleanup, not by direct delete |

`Holder` is a purge-time protection hook. `objects.LoadDependencies` auto-registers
holders from loaded modules; `objects.purge` consults every holder before deleting
from the requested repository. `objects.delete` is a direct repository command and
does not consult holders.

| Holder provider | Protected objects |
|---|---|
| `apphost` | app-owned persistent object holds in `apphost__object_holds` |
| `auth` | active indexed signed-contract objects used for authorization |
| `crypto` | indexed private-key objects and their corresponding public-key objects used for signing |
| `user` | active user asset rows |
13 changes: 10 additions & 3 deletions .ai/knowledge/modules/apphost.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Bridges local applications into the node over IPC and HTTP, letting them issue q
|---|---|
| `auth` | authorizes caller override with `SudoAction`, authorizes HTTP object reads with `ReadObjectAction`, signs/indexes app contracts, and searches signed contracts in the query preprocessor |
| `dir` | resolves identities from configured static tokens and HTTP `@alias/path` targets; formats the host alias in `HostInfoMsg` |
| `objects` | stores signed app contracts and serves `Objects.ReadDefault()` through HTTP `/.objects/<id>` |
| `objects` | stores signed app contracts, serves `Objects.ReadDefault()` through HTTP `/.objects/<id>`, and registers apphost as a purge holder provider |
| `user` (opt) | `PushToLocalSwarm` publishes signed app contracts after sign/install; current sign/install paths call it without a nil guard |
| `core/assets` | `Database()` backs `apphost__access_tokens` and `apphost__local_apps`; `LoadYAML` loads apphost config |

Expand All @@ -25,6 +25,7 @@ Bridges local applications into the node over IPC and HTTP, letting them issue q
- Create/list tokens: `apphost.create_token` writes random 32-char token with default 1-year expiry when duration is empty; `apphost.list_tokens` streams matching tokens and ends with `EOS`.
- Static tokens: `Prepare` resolves each `config.Tokens` identity -> deletes existing token row -> inserts a new token with a 100-year expiry.
- Install app: local `apphost.install_app` -> build `RelayForAction` contract for app and node -> `Auth.SignContract` -> `Auth.IndexContract` -> `Objects.Store` -> `CreateLocalApp` upsert -> async `User.PushToLocalSwarm`.
- Object holds: local `apphost.hold_object` inserts an app-owned hold with an optional `duration` arg, `apphost.unhold_object` deletes only the caller-owned hold, and `apphost.list_held_objects` streams the caller's active holds. `objects.purge` skips any object with at least one active apphost hold. Active means `hold_until IS NULL OR hold_until > now`; omitted duration writes `NULL` (infinite hold), otherwise `hold_until = now + duration`.
- HTTP bridge: bearer token -> `AuthenticateToken` -> set guest/host headers -> `/.objects/<id>` goes through `ReadObjectAction`; other paths route a query to header target, `@alias/path` target, or local node.

## Source
Expand All @@ -36,27 +37,33 @@ Bridges local applications into the node over IPC and HTTP, letting them issue q
- `mod/apphost/src/query_router.go`, `ipc_handler.go`, `query_preprocessor.go` - hosted app dispatch and relay-contract preprocessing.
- `mod/apphost/src/http_server.go`, `http_object_handler.go`, `http_query_handler.go` - bearer-auth HTTP bridge for objects and queries.
- `mod/apphost/src/op_*.go` - query operation handlers.
- `mod/apphost/src/access_tokens.go`, `db.go`, `db_access_token.go`, `db_local_app.go` - token/local-app persistence and lookup helpers.
- `mod/apphost/src/access_tokens.go`, `db.go`, `db_access_token.go`, `db_local_app.go`, `db_object_hold.go` - token, local-app, and object-hold persistence plus lookup helpers.
- `mod/apphost/src/object_holder.go` - objects holder hook backed by active app-owned hold rows.
- `mod/apphost/client/` - typed client wrappers for apphost ops.

## Surface

| What | Why it matters |
|--------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------|
| `apphost.create_token`, `apphost.list_tokens` | issue and stream app access tokens |
| `apphost.hold_object`, `apphost.unhold_object`, `apphost.list_held_objects` | manage persistent app-owned object holds |
| `objects.Holder` | prevents actively held app-owned objects from being purged |
| `apphost.register_handler`, `apphost.bind`, `apphost.cancel` | manage hosted app handlers and cancel in-flight guest queries |
| `apphost.new_app_contract`, `apphost.sign_app_contract`, `apphost.install_app` | create, sign, store, and index relay contracts for local apps |
| `Module.RouteQuery` | high-priority router that forwards target-addressed queries to registered local app handlers |
| `Module.PreprocessQuery` | attaches local app relay contracts and adds relay hops for apps hosted elsewhere |
| `config.Listen`, `config.BindHTTP` | configure IPC apphost listeners and the HTTP bridge |
| `apphost__access_tokens`, `apphost__local_apps` | persistent access tokens and installed-app records |
| `apphost__access_tokens`, `apphost__local_apps`, `apphost__object_holds` | persistent access tokens, installed-app records, and app-owned object holds |

## Invariants

- `apphost.install_app`, `apphost.register_handler`, and `apphost.bind` reject network-origin queries.
- `apphost.hold_object`, `apphost.unhold_object`, and `apphost.list_held_objects` reject network-origin queries and require a non-zero caller identity.
- Apps can list and unhold only their own hold rows; many apps may hold the same object.
- Anonymous IPC guests can route only when `allow_anonymous` is true and always lose `ZoneNetwork`.
- A guest can set `Caller` to another identity only when `auth.Authorize(SudoAction{Actor:guestID, AsID:Caller})` grants it.
- `apphost.list_tokens` always ends the stream with `EOS`.
- `CreateLocalApp` uses `OnConflict{DoNothing}`; reinstall does not update an existing row.
- `HoldObject` uses `OnConflict{DoNothing}`; duplicate holds are idempotent, holding does not require the object to exist locally, and `Duration` is `*astral.Duration` (nil = no expiry).
- `bind_http` empty disables the HTTP bridge.
- Handler endpoints are removed when dial fails during inbound routing.
9 changes: 6 additions & 3 deletions .ai/knowledge/modules/auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Decides whether an identity may perform a typed action, using local action handl
| Module | Why |
| --- | --- |
| `crypto` | signs contracts through `ObjectSigner` and `TextObjectSigner`; verifies issuer and subject signatures with ASN1 or BIP137 schemes |
| `objects` | loads signed contracts for `auth.index`; scans `RepoLocal` for startup indexing |
| `objects` | loads signed contracts for `auth.index`; scans `RepoLocal` for startup indexing; exposes active-contract object holds for purge |
| `secp256k1` | derives issuer and subject public keys from identities for signing and verification |
| `core/assets` | `Database()` backs `auth__contracts` and `auth__contract_permits`; `LoadYAML` loads the empty auth config |

Expand All @@ -21,6 +21,7 @@ Decides whether an identity may perform a typed action, using local action handl
- Sign one side: `SignIssuer` or `SignSubject` refuses an existing signature -> derives the identity public key with `secp256k1.FromIdentity` -> tries ASN1 object signing -> falls back to BIP137 text-object signing.
- Index contract op: `auth.index` loads the object ID through `Objects.ReadDefault()` -> requires `*SignedContract` -> `IndexContract` verifies and stores it -> sends `Ack`.
- Index contract: `indexMu` -> resolve object ID -> skip when a complete contract row already exists -> verify issuer and subject signatures according to signature scheme -> upsert contract row and insert permits if no permits exist yet.
- Object holding: `HoldObject` returns true for active indexed signed-contract object IDs so `objects.purge` skips contracts still used for authorization.
- Startup indexer: `Run` starts `indexer` -> scan `objects.RepoLocal` outside `ZoneNetwork` -> load each object -> index signed contracts and ignore other objects.
- Query contracts: `SignedContracts` builder filters by issuer, subject, active time window, and permit action type -> decodes stored signatures and permits back into `SignedContract` objects.

Expand All @@ -30,7 +31,7 @@ Decides whether an identity may perform a typed action, using local action handl
- `mod/auth/src/loader.go`, `module.go`, `deps.go`, `config.go`, `prepare.go` - module registration, dependency injection, router setup, database migration, and lifecycle.
- `mod/auth/src/authorize.go`, `authorizers.go` - handler dispatch, contract fallback, and built-in sudo authorization.
- `mod/auth/src/signing.go` - issuer and subject signing plus signature verification by scheme.
- `mod/auth/src/contracts.go`, `contract_query.go` - contract indexing, repository scan, and active-contract query builder.
- `mod/auth/src/contracts.go`, `contract_query.go`, `object_holder.go` - contract indexing, repository scan, active-contract query builder, and cleanup hold hook.
- `mod/auth/src/op_sign_contract.go`, `op_index.go` - query operation handlers.
- `mod/auth/src/db.go`, `db_contract.go`, `db_contract_permit.go` - GORM rows, contract upsert, permit persistence, and lookup filters.
- `mod/auth/client/` - typed client wrappers for auth operations.
Expand All @@ -42,14 +43,16 @@ Decides whether an identity may perform a typed action, using local action handl
| `Module.Authorize` and `Module.Add` | central extension point for modules that define typed authorization actions |
| `Module.SignContract`, `VerifyContract`, and `IndexContract` | contract lifecycle used by modules that delegate authority between identities |
| `Module.SignedContracts()` | builder used by authorization and callers that need active signed contract lookup |
| `objects.Holder` | prevents active indexed signed-contract objects from being purged |
| `auth.sign_contract`, `auth.index` | query methods for signing a contract object and indexing an already stored signed contract |
| `auth__contracts`, `auth__contract_permits` | persistent authorization index searched during contract fallback |

## Invariants

- Contracts never grant directly; they swap `action.Actor` to issuer and re-run local handlers.
- Contract path skips `Contract.Allows` and `Constrainable.ApplyConstraints`.
- Contract lookup filters `subject_id`, `starts_at <= now`, `expires_at` zero-or-future, joins permits by action `ObjectType`.
- Contract lookup filters `subject_id`, `starts_at <= now`, `expires_at > now`, joins permits by action `ObjectType`.
- `HoldObject` uses the same active time window as contract lookup and fails closed on DB errors.
- `contractExists` requires both signatures non-empty; partial rows re-index.
- `IndexContract` serialized by `indexMu`.
- `SignIssuer`/`SignSubject` refuse overwrite with `ErrAlreadySigned`.
Expand Down
Loading