No description
  • Go 98.3%
  • Dockerfile 1.2%
  • Makefile 0.5%
Find a file
zemdregon ad9108c3bb
Some checks are pending
CI / lint (push) Waiting to run
CI / test (push) Waiting to run
CI / build (push) Waiting to run
CI / docker (push) Blocked by required conditions
chore(deps): bump actions/setup-go to v7 (#26)
* chore(deps): bump actions/setup-go to v7

Self-hosted CI workflows.

* ci: setup-go v7 + cache false
2026-08-12 09:47:45 -05:00
.github chore(deps): bump actions/setup-go to v7 (#26) 2026-08-12 09:47:45 -05:00
cmd/module chore: align module with starter template and CI 2026-07-22 19:09:18 -05:00
deploy chore: align module with starter template and CI 2026-07-22 19:09:18 -05:00
internal Advertise settings capability (v0.3.3). 2026-08-10 04:37:08 -05:00
test refactor: align with muxcore-module-starter template 2026-06-12 11:49:49 -05:00
.dockerignore refactor: align with muxcore-module-starter template 2026-06-12 11:49:49 -05:00
.env.example chore: align module with starter template and CI 2026-07-22 19:09:18 -05:00
.gitignore chore: align module with starter template and CI 2026-07-22 19:09:18 -05:00
.golangci.yml ci: set explicit golangci-lint config version (#18) 2026-08-09 19:28:56 -05:00
CHANGELOG.md Advertise settings capability (v0.3.3). 2026-08-10 04:37:08 -05:00
COMPATIBILITY.md chore: align module with starter template and CI 2026-07-22 19:09:18 -05:00
CONTRIBUTING.md chore: align module with starter template and CI 2026-07-22 19:09:18 -05:00
Dockerfile chore(deps): bump alpine from 3.21 to 3.24 2026-07-01 15:49:23 +00:00
go.mod Expose policy_file via RegisterSettings mesh. 2026-08-10 02:59:15 -05:00
go.sum Expose policy_file via RegisterSettings mesh. 2026-08-10 02:59:15 -05:00
LICENSE chore: add LICENSE, SECURITY.md, CHANGELOG.md, CONTRIBUTING.md, COMPATIBILITY.md, .env.example, Makefile, .golangci.yml, Dockerfile, .dockerignore 2026-06-10 06:55:42 -05:00
Makefile chore: add LICENSE, SECURITY.md, CHANGELOG.md, CONTRIBUTING.md, COMPATIBILITY.md, .env.example, Makefile, .golangci.yml, Dockerfile, .dockerignore 2026-06-10 06:55:42 -05:00
muxcore.json Advertise settings capability (v0.3.3). 2026-08-10 04:37:08 -05:00
policies.yaml feat: allow media-scanner to write to storage 2026-06-19 15:17:59 -05:00
README.md Add dynamic call policy grants via mesh event bus. 2026-08-09 21:27:08 -05:00
ROADMAP.md Add dynamic call policy grants via mesh event bus. 2026-08-09 21:27:08 -05:00
SECURITY.md chore: add LICENSE, SECURITY.md, CHANGELOG.md, CONTRIBUTING.md, COMPATIBILITY.md, .env.example, Makefile, .golangci.yml, Dockerfile, .dockerignore 2026-06-10 06:55:42 -05:00

Call Policy Default

Default inter-module call access control for MuxCore.

Without this module, every cross-module gRPC call is denied by default. Core refuses all mesh.Call() requests until a module implementing CallPolicyProvider registers with capability "call.policy".

How It Works

The module loads a static YAML policy (policies.yaml) that declares which callers may invoke which targets and methods. The mesh client consults this module before dispatching every Call().

Module A calls Module B
        │
        ▼
mesh.Client.Call()
        │
        ▼
call-policy-default.AllowCall("moduleA", "moduleB", "method")
        │
        ▼
  allowed? ───yes──→ dispatch call
    │
   no
    │
    ▼
  return "call denied" error

Configuration

Policy File (policies.yaml)

Rules are evaluated in order; the first match wins. If no rule matches, the call is denied. Wildcard "*" matches any caller, target, or method.

# Allow module to call any method on any target
- caller: "downloader-qbittorrent"
  target: "*"
  methods: ["*"]

# Allow specific call patterns
- caller: "media-movies"
  target: "transcoder-ffmpeg"
  methods: ["Transcode", "Status"]

# Development mode: allow all (uncomment only for local use)
# - caller: "*"
#   target: "*"
#   methods: ["*"]

If the policy file is missing or invalid at startup, Init fails. Ship and maintain an explicit policies.yaml (the repo includes a starter file).

Environment

Variable Default Description
CALL_POLICY_FILE policies.yaml Path to policy YAML file
CALL_POLICY_GRPC_ADDR :9101 Listen address for this module's gRPC server
MUXCORE_INSECURE_DISABLE_TLS unset Set to true for insecure mesh registration (dev)

Mesh registration also uses the module SDK (MUXCORE_GRPC_ADDR, MUXCORE_MODULE_ID, --muxcore-mesh-addr, --muxcore-module-id).

Advanced rules (v0.2+)

groups:
  media-managers:
    - media-movies
    - media-tv
rules:
  - caller_group: media-managers
    target: "transcoder-ffmpeg"
    methods: ["Transcode"]
    rate_limit_per_min: 30
    after: "08:00"
    before: "22:00"
    days: ["mon", "tue", "wed", "thu", "fri"]

Legacy files that are a bare YAML list of rules still work.

Dynamic grants (v0.3+)

Modules can request temporary access at runtime by publishing mesh events:

Event Payload
call.policy.grant {"id":"optional","caller":"mod-a","target":"mod-b","methods":["Call"],"ttl_seconds":300}
call.policy.revoke {"id":"optional"} or {"caller":"mod-a","target":"mod-b"}

Grants are evaluated after static YAML rules. They survive SIGHUP reloads and expire when ttl_seconds elapses (0 = until revoke / process exit).

Hot-Reload

SIGHUP reloads the policy file without restarting the module (dynamic grants are kept).

Implementation

  • Registers with capability: "call.policy"
  • Provides muxcore.policy.v1.PolicyService (sidecar); core wires it as contracts.CallPolicyProvider
  • Method-level control via each rule's methods list (including "*")
  • AllowPublish always denies — deploy publish-policy-default for publish policy
  • Denied calls are audited by core at mesh enforcement (not via module AuditLogger); module keeps counters/slog
  • Registers grpc_health_v1 (SERVING) on the module gRPC server
  • Tracks counters call_policy_allowed_total / call_policy_denied_total (PolicyServer.Metrics()); no HTTP metrics endpoint