Skip to content
Merged
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
24 changes: 20 additions & 4 deletions api/ai_gateway.proto
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,27 @@ option go_package = "github.com/liaisonio/liaison/api/ai/v1";
// Uses the same key ownership, model allowlist, quota and revocation checks.
// GET/PUT /api/v1/ai/applications/{id}; POST .../{id}/probe
message ApplicationConfig {
string protocol = 1; // openai-compatible, anthropic or ollama (native /api/chat)
string protocol = 1; // API profile: openai includes Responses; openai-compatible is Chat Completions only (default for new OpenAI apps). Other profiles: anthropic, ark, qwen, gemini, ollama.
string base_path = 2;
bool tls = 3;
string api_key = 4; // Write-only; empty preserves. Bound to target fingerprint.
bool clear_key = 5;
bool has_api_key = 6; // Read-only.
string application_type = 7; // Read-only protocol family. OpenAI permits both API profiles; legacy llm remains configurable.
}
// GET/PUT /api/v1/ai/accesses/{id}
message AccessConfig {
bool enabled = 1;
map<string,string> models = 2; // Public alias -> upstream model.
string external_protocol = 3; // V1: openai-compatible.
string external_protocol = 3; // Derived from upstream capability, never an arbitrary conversion switch.
}
// GET /api/v1/ai/accesses/{id}/workspace: consumer-safe view, no upstream targets.
message AccessWorkspace {
string name = 1;
bool enabled = 2;
repeated string models = 3;
bool can_manage = 4;
repeated string external_protocols = 5; // Consumer-safe capabilities; includes anthropic only for native Anthropic upstreams.
repeated string external_protocols = 5; // Consumer-safe native and implemented conversion protocols; Gemini/Qwen native only.
}
// GET/POST /api/v1/ai/accesses/{id}/keys; DELETE .../keys/{key_id}
message KeyRequest {
Expand Down Expand Up @@ -70,7 +71,8 @@ message RequestRecord {
bool complete = 7;
uint64 key_id = 8; // Zero for a dashboard-authenticated debug request.
}
// GET /api/v1/ai/accesses/{id}/usage: own usage, rolling 30 days.
// GET /api/v1/ai/accesses/{id}/usage: own usage.
// Optional hours query: 1, 6, 24, 168, 720. Default 720 (rolling 30 days).
// Independent of the 500-request log retention. No historical backfill.
// Missing upstream usage remains null, not measured zero. No billing guarantee.
message TokenUsageRecord {
Expand Down Expand Up @@ -98,3 +100,17 @@ message TokenUsageResponse {
// POST /api/v1/ai/accesses/{id}/v1/chat/completions
// Protocol-native JSON/SSE, no management response envelope. No cookies/CORS.
// POST /api/v1/ai/accesses/{id}/test: authenticated owner's bounded debug request.
// Additional native operations below the access root:
// OpenAI: POST v1/responses (stateless only).
// Ark: POST api/v3/chat/completions and api/v3/responses.
// Qwen: POST api/v1/services/aigc/text-generation/generation;
// X-DashScope-SSE: enable selects SSE; no arbitrary headers forwarded.
// Gemini: POST v1beta/models/{alias}:generateContent or :streamGenerateContent?alt=sse;
// Liaison key in x-goog-api-key or Authorization, never query parameters.
// Ollama: POST api/chat; GET api/tags. No pull/delete/create or arbitrary paths.
// Ollama chat defaults to streaming NDJSON; stream:false returns native JSON.
// Keep-alive/unload, empty-message loading and resource options are not consumer
// capabilities. tags returns authorized aliases only, not upstream model metadata.
// Requests/streams share ownership, model alias, quota, revocation and audit checks.
// Responses previous_response_id/conversation/background and cached/file resource
// references are not exposed without a separate user-scoped ownership registry.
55 changes: 43 additions & 12 deletions api/v1/liaison.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions api/v1/liaison.proto
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ message Proxy {
string effective_status_message = 11 [json_name = "effective_status_message"];
bool expose_public_port = 12 [json_name = "expose_public_port"];
string access_protocol = 13 [json_name = "access_protocol"];
string http_entry_mode = 14 [json_name = "http_entry_mode"];
}

message Proxies {
Expand Down Expand Up @@ -286,6 +287,7 @@ message CreateProxyRequest {
// Supported selections: tcp, http, ssh, webssh, websftp, web, aiapi.
// Native RDP/VNC/database servers are not implemented; use tcp or web.
string access_protocol = 6 [json_name = "access_protocol"];
string http_entry_mode = 7 [json_name = "http_entry_mode"];
}

message CreateProxyResponse {
Expand All @@ -304,6 +306,7 @@ message UpdateProxyRequest {
optional bool expose_public_port = 6 [json_name = "expose_public_port"];
// Explicit selections use the same supported protocols as creation.
string access_protocol = 7 [json_name = "access_protocol"];
string http_entry_mode = 8 [json_name = "http_entry_mode"];
}

message UpdateProxyResponse {
Expand Down Expand Up @@ -483,6 +486,8 @@ service LiaisonService {
body: "*"
};
};
// Revoke the current JWT session persistently; other sessions remain valid.
// PATs must use their dedicated revocation endpoint.
rpc Logout(LogoutRequest) returns (LogoutResponse) {
option (google.api.http) = {
post: "/api/v1/iam/logout"
Expand Down
20 changes: 20 additions & 0 deletions api/web_entry.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
syntax = "proto3";
package liaison.webentry.v1;
option go_package = "github.com/liaisonio/liaison/api/webentry/v1";

// HTTP-only supplementary contract, like agent_settings.proto.
// GET /api/v1/web-entries/capabilities requires an active console user.
message Capabilities { bool domain = 1; }
// POST /api/v1/web-entries/{id}/launch requires Bearer console authentication,
// accesses.use, resource visibility and source-IP policy. No request body fields.
// Response envelope: {code:200,data:{url:...}}.
// URL contains a one-use 30-second ticket, never a console JWT/PAT. Must not be
// logged/shared. On successful consumption the gateway sets an HttpOnly cookie
// scoped to this access and redirects to a clean URL. Sessions last one hour.
// Path-mode URLs use /access/{id}/web/. Legacy /_liaison/a/{id}/ routes remain
// available with the same authorization and prefix-scoped cookies.
message LaunchResult { string url = 1; }
// Proxy/CreateProxyRequest/UpdateProxyRequest add http_entry_mode in v1/liaison.proto:
// path, port, domain. Existing empty persisted values are port. Omitted updates
// preserve the mode; new HTTP entries default to path unless a public port is
// explicitly requested. Domain requires configured wildcard DNS and TLS.
9 changes: 9 additions & 0 deletions api/webdata_capabilities.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
syntax = "proto3";
package liaison.webdata_capabilities;
option go_package = "github.com/liaisonio/liaison/api/webdata_capabilities;webdata_capabilities";

// Supplementary HTTP contract. GET /api/v1/webdata/capabilities requires an
// active authenticated console user. No upstream configuration is returned.
// Envelope: {code:200,message:"success",data:{dameng:true}} in standard builds.
// A build capability does not grant permission to create or use resources.
message Capabilities { bool dameng = 1; }
20 changes: 20 additions & 0 deletions api/websmb.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
syntax = "proto3";
package liaison.websmb;
option go_package = "github.com/liaisonio/liaison/api/websmb;websmb";

// Sessions and encrypted credentials use the existing WebData API, protocol=smb.
// database is one share name; schema is the optional NTLM domain.
// GET /api/v1/webdata/sessions/{token}/smb/list?path=/directory
// GET /api/v1/webdata/sessions/{token}/smb/preview?path=/file
// GET /api/v1/webdata/sessions/{token}/smb/download?path=/file
// Requires session ownership, active access and the existing files-read feature.
// Read-only first release: no uploads, deletes, renames, SMB1 or DFS referrals.
message Entry {
string name = 1;
int64 size = 2;
string mode = 3;
bool directory = 4;
bool symlink = 5;
string modified_at = 6;
}
message Preview { string text = 1; }
5 changes: 5 additions & 0 deletions deploy/docker/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ LIAISON_PUBLIC_HOST=your-public-ip-or-domain
# is the port directly bound on the host. Default 443 (HTTPS).
MANAGER_PORT=443

# Optional shared Web subdomains, e.g. apps.example.com. Before installation,
# place a matching wildcard certificate/key in certs/web.crt and certs/web.key.
# Configure wildcard DNS to this server. Empty keeps the domain option hidden.
LIAISON_WEB_DOMAIN=

# Frontier edgebound port — connectors dial this to reach the gateway.
# Bound on the host (not via docker-proxy).
FRONTIER_PORT=30012
Expand Down
2 changes: 2 additions & 0 deletions deploy/docker/conf/liaison.yaml.template
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ manager:
certs:
- cert: /opt/liaison/certs/server.crt
key: /opt/liaison/certs/server.key
${WEB_TLS_CERTS}
db: /opt/liaison/data/liaison.db
packages_dir: /opt/liaison/edge
web_dir: /opt/liaison/web
frontier_edge_port: ${FRONTIER_PORT}
server_url: ${SERVER_URL}
web_domain: "${LIAISON_WEB_DOMAIN}"
jwt_secret: ${JWT_SECRET}
ssh_host_key_file: /opt/liaison/data/ssh_host_ed25519_key
ssh_idle_timeout: 30m
Expand Down
1 change: 1 addition & 0 deletions deploy/docker/docker-compose.release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ services:
- guacd
environment:
LIAISON_PUBLIC_HOST: ${LIAISON_PUBLIC_HOST:-localhost}
LIAISON_WEB_DOMAIN: ${LIAISON_WEB_DOMAIN:-}
MANAGER_PORT: ${MANAGER_PORT:-443}
FRONTIER_PORT: ${FRONTIER_PORT:-30012}
FRONTIER_CONTROLPLANE_PORT: ${FRONTIER_CONTROLPLANE_PORT:-30010}
Expand Down
1 change: 1 addition & 0 deletions deploy/docker/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ services:
- guacd
environment:
LIAISON_PUBLIC_HOST: ${LIAISON_PUBLIC_HOST:-localhost}
LIAISON_WEB_DOMAIN: ${LIAISON_WEB_DOMAIN:-}
MANAGER_PORT: ${MANAGER_PORT:-443}
FRONTIER_PORT: ${FRONTIER_PORT:-30012}
FRONTIER_CONTROLPLANE_PORT: ${FRONTIER_CONTROLPLANE_PORT:-30010}
Expand Down
17 changes: 16 additions & 1 deletion deploy/docker/entrypoint-liaison.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,21 @@ mkdir -p "$DATA_DIR" "$CERTS_DIR" "$LOG_DIR"
: "${AGENT_REQUEST_TIMEOUT:=2m}"
: "${AGENT_MAX_MODEL_STEPS:=12}"
: "${AGENT_APPROVAL_EXPIRY:=15m}"
: "${LIAISON_WEB_DOMAIN:=}"
WEB_TLS_CERTS=""
if [ -n "$LIAISON_WEB_DOMAIN" ]; then
if ! printf '%s' "$LIAISON_WEB_DOMAIN" | grep -Eq '^[A-Za-z0-9.-]+$'; then
echo "[entrypoint] invalid LIAISON_WEB_DOMAIN" >&2
exit 1
fi
if [ ! -r "$CERTS_DIR/web.crt" ] || [ ! -r "$CERTS_DIR/web.key" ]; then
echo "[entrypoint] domain entries require certs/web.crt and certs/web.key" >&2
exit 1
fi
WEB_TLS_CERTS=' - cert: /opt/liaison/certs/web.crt
key: /opt/liaison/certs/web.key'
fi
export WEB_TLS_CERTS LIAISON_WEB_DOMAIN

# server_url: omit :PORT for the well-known TLS / HTTP defaults so the URL
# baked into the web console / install commands is canonical.
Expand All @@ -50,7 +65,7 @@ if [ ! -f "$CONF_DIR/liaison.yaml" ]; then
export FRONTIER_PORT FRONTIER_CONTROLPLANE_PORT MANAGER_PORT SERVER_URL JWT_SECRET GUACD_ADDR GUACD_BRIDGE_ADDR GUACD_BRIDGE_HOST
export AGENT_ENABLED AGENT_BASE_URL AGENT_MODEL AGENT_REQUEST_TIMEOUT AGENT_MAX_MODEL_STEPS AGENT_APPROVAL_EXPIRY
# shellcheck disable=SC2016
envsubst '${FRONTIER_PORT} ${FRONTIER_CONTROLPLANE_PORT} ${MANAGER_PORT} ${SERVER_URL} ${JWT_SECRET} ${GUACD_ADDR} ${GUACD_BRIDGE_ADDR} ${GUACD_BRIDGE_HOST} ${AGENT_ENABLED} ${AGENT_BASE_URL} ${AGENT_MODEL} ${AGENT_REQUEST_TIMEOUT} ${AGENT_MAX_MODEL_STEPS} ${AGENT_APPROVAL_EXPIRY}' \
envsubst '${FRONTIER_PORT} ${FRONTIER_CONTROLPLANE_PORT} ${MANAGER_PORT} ${SERVER_URL} ${JWT_SECRET} ${GUACD_ADDR} ${GUACD_BRIDGE_ADDR} ${GUACD_BRIDGE_HOST} ${AGENT_ENABLED} ${AGENT_BASE_URL} ${AGENT_MODEL} ${AGENT_REQUEST_TIMEOUT} ${AGENT_MAX_MODEL_STEPS} ${AGENT_APPROVAL_EXPIRY} ${WEB_TLS_CERTS} ${LIAISON_WEB_DOMAIN}' \
< "$CONF_DIR/liaison.yaml.template" > "$CONF_DIR/liaison.yaml"
echo "[entrypoint] rendered $CONF_DIR/liaison.yaml (public_host=$LIAISON_PUBLIC_HOST manager_port=$MANAGER_PORT frontier_port=$FRONTIER_PORT controlplane_port=$FRONTIER_CONTROLPLANE_PORT)"
fi
Expand Down
17 changes: 17 additions & 0 deletions deploy/docker/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,23 @@ mkdir -p data certs logs
# (Docker Desktop on macOS/Windows auto-maps UIDs anyway).
chown 1000:1000 data certs logs 2>/dev/null || true

# Optional wildcard Web entry domain. Do not generate a certificate for it or
# enable it implicitly: the operator supplies both DNS and a trusted certificate.
if [ -n "${LIAISON_WEB_DOMAIN:-}" ]; then
if ! printf '%s' "$LIAISON_WEB_DOMAIN" | grep -Eq '^[A-Za-z0-9.-]+$'; then
err "Invalid LIAISON_WEB_DOMAIN"; exit 1
fi
if [ ! -s certs/web.crt ] || [ ! -s certs/web.key ]; then
err "Domain entries require certs/web.crt and certs/web.key before installation."; exit 1
fi
if ! openssl x509 -in certs/web.crt -noout -checkend 0 >/dev/null 2>&1; then
err "Web domain certificate is invalid or expired."; exit 1
fi
chmod 600 certs/web.key
chown 1000:1000 certs/web.crt certs/web.key 2>/dev/null || true
log "==> Web domain configured; the manager will verify wildcard coverage and key pairing"
fi

FRESH_INSTALL=0
if [ ! -f data/.initialized ]; then
FRESH_INSTALL=1
Expand Down
2 changes: 2 additions & 0 deletions docs/assets/integrations/SOURCES.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,5 @@ Ollama uses the existing [Simple Icons Ollama mark](https://github.com/simple-ic
`memcached.svg` is the existing Memcached mark from
[SVG Logos by Gil Barbara](https://github.com/gilbarbara/logos/blob/main/logos/memcached.svg).
Used to identify the accessed service; brand rights remain with their owners.

- `qwen.svg`, `ark.svg`: Lobe Icons static SVG 1.90.0 (`qwen-color.svg`, `volcengine-color.svg`), MIT; https://github.com/lobehub/lobe-icons . Existing LICENSE-lobe-icons.txt applies.
Loading
Loading