← Public packages
@kentcdodds/onepassword
Resolve 1Password Connect item fields for secret-aware fetch with website host allowlisting.
connect/source.ts
227 lines · 6.7 KB · TypeScriptconst appNameDefault = 'kody-onepassword-connect'
const regionDefault = 'ams'
const credentialsPath = '/home/opuser/.op/1password-credentials.json'
const dataMountPath = '/opdata'
const dockerCompose = [
'version: "3.4"',
'',
'services:',
' connect-sync:',
' image: 1password/connect-sync:latest',
' environment:',
` OP_SESSION: "${credentialsPath}"`,
` XDG_DATA_HOME: "${dataMountPath}"`,
' OP_HTTP_PORT: "8081"',
' OP_BUS_PORT: "11221"',
' OP_BUS_PEERS: "localhost:11220"',
' volumes:',
` - "./1password-credentials.json:${credentialsPath}"`,
` - "opdata:${dataMountPath}"`,
' connect-api:',
' image: 1password/connect-api:latest',
' ports:',
' - "8080:8080"',
' environment:',
` OP_SESSION: "${credentialsPath}"`,
` XDG_DATA_HOME: "${dataMountPath}"`,
' OP_HTTP_PORT: "8080"',
' OP_BUS_PORT: "11220"',
' OP_BUS_PEERS: "localhost:11221"',
' OP_SYNC_TIMEOUT: "60s"',
' volumes:',
` - "./1password-credentials.json:${credentialsPath}"`,
` - "opdata:${dataMountPath}"`,
'',
'volumes:',
' opdata:',
'',
].join('\n')
const flyToml = [
`app = "${appNameDefault}"`,
`primary_region = "${regionDefault}"`,
'',
'[build]',
' # Prefer Machines API multi-container deploy via ./connect/deploy-fly.',
' # Official images: 1password/connect-api:latest + 1password/connect-sync:latest',
'',
'[http_service]',
' internal_port = 8080',
' force_https = true',
' auto_stop_machines = false',
' auto_start_machines = true',
' min_machines_running = 1',
'',
'[[vm]]',
' size = "shared-cpu-1x"',
' memory = "1024mb"',
' cpus = 1',
'',
'[mounts]',
' source = "opdata"',
` destination = "${dataMountPath}"`,
'',
].join('\n')
const machineConfigJson = `${JSON.stringify(
{
region: regionDefault,
config: {
guest: { cpu_kind: 'shared', cpus: 1, memory_mb: 1024 },
files: [
{
guest_path: credentialsPath,
raw_value:
'<Base64(1password-credentials.json) from ONEPASSWORD_CONNECT_OP_SESSION>',
},
],
containers: [
{
name: 'connect-sync',
image: '1password/connect-sync:latest',
env: {
OP_SESSION: credentialsPath,
XDG_DATA_HOME: dataMountPath,
OP_HTTP_PORT: '8081',
OP_BUS_PORT: '11221',
OP_BUS_PEERS: 'localhost:11220',
},
mounts: [{ volume: '<opdata volume id>', path: dataMountPath }],
},
{
name: 'connect-api',
image: '1password/connect-api:latest',
env: {
OP_SESSION: credentialsPath,
XDG_DATA_HOME: dataMountPath,
OP_HTTP_PORT: '8080',
OP_BUS_PORT: '11220',
OP_BUS_PEERS: 'localhost:11221',
OP_SYNC_TIMEOUT: '60s',
},
mounts: [{ volume: '<opdata volume id>', path: dataMountPath }],
healthchecks: [
{
name: 'api-heartbeat',
http: {
port: 8080,
method: 'GET',
path: '/heartbeat',
scheme: 'http',
},
grace_period: 90,
interval: 15,
timeout: 5,
success_threshold: 1,
failure_threshold: 5,
},
],
},
],
services: [
{
protocol: 'tcp',
internal_port: 8080,
autostart: true,
autostop: false,
ports: [
{ port: 80, handlers: ['http'], force_https: true },
{ port: 443, handlers: ['tls', 'http'] },
],
},
],
},
},
null,
2,
)}\n`
const readme = [
'# Kody 1Password Connect (Fly)',
'',
'Runs official `1password/connect-api` + `1password/connect-sync` on one Fly Machine',
'(multi-container). Credentials are a **file** (`OP_SESSION` = path). SQLite data lives on',
`persistent volume \`opdata\` mounted at \`${dataMountPath}\` via \`XDG_DATA_HOME\` so`,
'`/home/opuser/.op` stays owned by `opuser`. HTTPS via Fly proxy → connect-api:8080.',
'',
'## Required secrets (Kody names)',
'',
'- `ONEPASSWORD_CONNECT_OP_SESSION` — Base64(`1password-credentials.json`) (no newlines).',
' deploy-fly writes this via Machines `config.files.raw_value` and sets container env',
` \`OP_SESSION=${credentialsPath}\` (path, not Base64).`,
'- `flyApiToken` — Machines API + GraphQL for app/machine/IP/volumes.',
'',
'Client / sealed provider door key (not a Connect container env):',
'',
'- `ONEPASSWORD_CONNECT_TOKEN` — Bearer token for `/v1/*` and `secretProviderBind`.',
'',
'## Deploy',
'',
'```js',
"import deploy from 'kody:@kentcdodds/onepassword/connect/deploy-fly'",
'await deploy()',
'```',
'',
`Default app: \`${appNameDefault}\` → \`https://${appNameDefault}.fly.dev\`.`,
'',
].join('\n')
const files: Record<string, string> = {
'docker-compose.yaml': dockerCompose,
'fly.toml': flyToml,
'machine-config.json': machineConfigJson,
'README.md': readme,
'NOTES.md': [
'# Notes',
'',
'- Fly multi-container Machines share a network namespace → use localhost peers',
' with distinct `OP_BUS_PORT` values (11220 / 11221) and distinct `OP_HTTP_PORT`.',
'- Prefer `./connect/deploy-fly` (Machines API) over flyctl; no custom Dockerfile.',
`- Shared data uses named temp_dir volume \`${dataMountPath}\` (\`XDG_DATA_HOME\`), not temp_dir`,
' and not `/home/opuser/.op/data` (volume ownership breaks ConfigDir checks).',
`- Credentials file at \`${credentialsPath}\`; \`OP_SESSION\` is that path.`,
'- Do not set Fly app secret `OP_SESSION` to Base64 — that overrides the path env.',
'- Sync starts first (no depends_on api). API uses `OP_SYNC_TIMEOUT=60s`.',
'',
].join('\n'),
}
/**
* Default callable for `kody:@kentcdodds/onepassword/connect/source`.
*
* Use this source entrypoint when a Kody workflow needs deployable 1Password Connect
* Fly/Docker files (compose, machine-config, fly.toml) without secret values.
*/
export default async function getOnepasswordConnectSource() {
return {
name: appNameDefault,
description:
'Fly multi-container 1Password Connect Server (connect-api + connect-sync) for Kody sealed secret provider.',
files,
env: {
required: ['OP_SESSION'],
optional: [
'OP_HTTP_PORT',
'OP_BUS_PORT',
'OP_BUS_PEERS',
'OP_LOG_LEVEL',
'OP_SYNC_TIMEOUT',
'XDG_DATA_HOME',
],
kodySecrets: [
'ONEPASSWORD_CONNECT_OP_SESSION',
'flyApiToken',
'ONEPASSWORD_CONNECT_TOKEN',
],
},
deployNotes: [
'Use kody:@kentcdodds/onepassword/connect/deploy-fly for Machines API deploy.',
'Save ONEPASSWORD_CONNECT_OP_SESSION as Base64(credentials.json) before deploy.',
'Deploy mounts credentials via config.files and sets OP_SESSION to the file path.',
'Shared temp_dir opdata at /opdata (XDG_DATA_HOME); unset Fly OP_SESSION env secret.',
'HTTPS terminates at Fly proxy → connect-api internal 8080.',
'Bind sealed provider with connectHost https://kody-onepassword-connect.fly.dev after smoke.',
],
}
}