@orchestraworks/cli 0.5.1 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli/api/compute-provider-check.d.ts +29 -0
- package/dist/cli/api/compute-provider-check.js +207 -0
- package/dist/cli/api/tail.d.ts +66 -0
- package/dist/cli/api/tail.js +564 -0
- package/dist/cli/main.d.ts +5 -1
- package/dist/cli/main.js +22 -0
- package/dist/constructs/agent.d.ts +10 -0
- package/dist/constructs/agent.js +39 -4
- package/dist/constructs/environment.d.ts +29 -1
- package/dist/constructs/environment.js +28 -1
- package/dist/constructs/skill.d.ts +6 -1
- package/dist/constructs/skill.js +21 -2
- package/dist/engine/reconcile.js +15 -1
- package/dist/generated/cli-commands.json +876 -1
- package/dist/generated/managed-skills.d.ts +2 -0
- package/dist/generated/managed-skills.js +13 -0
- package/dist/index.d.ts +1 -1
- package/docs/REFERENCE.md +21 -1
- package/node_modules/@orchestraworks/client/dist/esm/models/ApiKey.d.ts +6 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/ApiKey.js +2 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/ComputeProvider.d.ts +3 -3
- package/node_modules/@orchestraworks/client/dist/esm/models/CreateApiKeyRequest.d.ts +7 -1
- package/node_modules/@orchestraworks/client/dist/esm/models/CreateApiKeyRequest.js +2 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/CreateEnvironmentRequest.d.ts +13 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/CreateEnvironmentRequest.js +5 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/Environment.d.ts +13 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/Environment.js +5 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHook.d.ts +38 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHook.js +45 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHooks.d.ts +39 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHooks.js +44 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHooksRequest.d.ts +39 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHooksRequest.js +44 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentProvisionSpec.d.ts +2 -1
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentProvisionSpecRequest.d.ts +2 -1
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentSnapshot.d.ts +19 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentSnapshot.js +7 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/Machine.d.ts +7 -1
- package/node_modules/@orchestraworks/client/dist/esm/models/Machine.js +2 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/UpdateEnvironmentRequest.d.ts +13 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/UpdateEnvironmentRequest.js +5 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/index.d.ts +3 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/index.js +3 -0
- package/node_modules/@orchestraworks/client/dist/models/ApiKey.d.ts +6 -0
- package/node_modules/@orchestraworks/client/dist/models/ApiKey.js +2 -0
- package/node_modules/@orchestraworks/client/dist/models/ComputeProvider.d.ts +3 -3
- package/node_modules/@orchestraworks/client/dist/models/CreateApiKeyRequest.d.ts +7 -1
- package/node_modules/@orchestraworks/client/dist/models/CreateApiKeyRequest.js +2 -0
- package/node_modules/@orchestraworks/client/dist/models/CreateEnvironmentRequest.d.ts +13 -0
- package/node_modules/@orchestraworks/client/dist/models/CreateEnvironmentRequest.js +5 -0
- package/node_modules/@orchestraworks/client/dist/models/Environment.d.ts +13 -0
- package/node_modules/@orchestraworks/client/dist/models/Environment.js +5 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentHook.d.ts +38 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentHook.js +52 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentHooks.d.ts +39 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentHooks.js +51 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentHooksRequest.d.ts +39 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentHooksRequest.js +51 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentProvisionSpec.d.ts +2 -1
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentProvisionSpecRequest.d.ts +2 -1
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentSnapshot.d.ts +19 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentSnapshot.js +7 -0
- package/node_modules/@orchestraworks/client/dist/models/Machine.d.ts +7 -1
- package/node_modules/@orchestraworks/client/dist/models/Machine.js +2 -0
- package/node_modules/@orchestraworks/client/dist/models/UpdateEnvironmentRequest.d.ts +13 -0
- package/node_modules/@orchestraworks/client/dist/models/UpdateEnvironmentRequest.js +5 -0
- package/node_modules/@orchestraworks/client/dist/models/index.d.ts +3 -0
- package/node_modules/@orchestraworks/client/dist/models/index.js +3 -0
- package/node_modules/@orchestraworks/client/package.json +1 -1
- package/package.json +4 -4
- package/skills/orchestra/SKILL.md +167 -42
- package/skills/orchestra-fdk/SKILL.md +112 -545
- package/skills/orchestra-fdk/references/authoring.md +130 -3
- package/skills/orchestra-fdk/references/environment.md +352 -43
- package/skills/orchestra-fdk/references/integrations/analytics.md +18 -0
- package/skills/orchestra-fdk/references/integrations/ci-cd.md +20 -0
- package/skills/orchestra-fdk/references/integrations/cloud.md +19 -0
- package/skills/orchestra-fdk/references/integrations/code-repo.md +76 -0
- package/skills/orchestra-fdk/references/integrations/databases.md +22 -0
- package/skills/orchestra-fdk/references/integrations/dependencies.md +29 -0
- package/skills/orchestra-fdk/references/integrations/design.md +18 -0
- package/skills/orchestra-fdk/references/integrations/feature-flags.md +19 -0
- package/skills/orchestra-fdk/references/integrations/incident.md +29 -0
- package/skills/orchestra-fdk/references/integrations/issue-tracker.md +65 -0
- package/skills/orchestra-fdk/references/integrations/knowledge-base.md +43 -0
- package/skills/orchestra-fdk/references/integrations/messaging.md +38 -0
- package/skills/orchestra-fdk/references/integrations/observability.md +36 -0
- package/skills/orchestra-fdk/references/integrations/secrets-managers.md +25 -0
- package/skills/orchestra-fdk/references/integrations/support-desk.md +31 -0
- package/skills/orchestra-fdk/references/phases/0-start.md +62 -0
- package/skills/orchestra-fdk/references/phases/1-discover.md +111 -0
- package/skills/orchestra-fdk/references/phases/2-plan.md +157 -0
- package/skills/orchestra-fdk/references/phases/3-connect.md +99 -0
- package/skills/orchestra-fdk/references/phases/4-build.md +159 -0
- package/skills/orchestra-fdk/references/phases/5-prove.md +107 -0
- package/skills/orchestra-fdk/references/phases/6-handover.md +42 -0
- package/skills/orchestra-fdk/references/troubleshooting.md +128 -0
- package/templates/bug-fix/agents/bugfix.md +1 -1
- package/templates/bug-fix/main.ts +1 -1
- package/templates/engineering-team/README.md +45 -181
- package/templates/engineering-team/agents/engineer-agent.md +10 -7
- package/templates/engineering-team/agents/manager-agent.md +23 -120
- package/templates/engineering-team/inputs.json +1 -3
- package/templates/engineering-team/lib/environment.ts +10 -90
- package/templates/engineering-team/lib/inputs.ts +5 -97
- package/templates/engineering-team/lib/setup.sh +5 -5
- package/templates/engineering-team/main.ts +22 -69
- package/templates/todo-factory/agents/bugfix.md +1 -1
- package/templates/todo-factory/main.ts +1 -1
- package/templates/engineering-team/agents/engineer-bare.md +0 -22
- package/templates/engineering-team/onboarding/create-score-metrics.sh +0 -33
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Analytics
|
|
2
|
+
|
|
3
|
+
The agents read product usage to judge a change, or pull it into the platform's custom metrics. A pull that
|
|
4
|
+
needs no judgment fits a `script` agent on a schedule (orchestra skill, section 2). Give access with a Secret
|
|
5
|
+
the network edge adds, with read scopes only. Egress is open, so add only the rule that adds the credential.
|
|
6
|
+
The agent installs or uses whatever client it prefers. The edge adds the credential to its requests.
|
|
7
|
+
|
|
8
|
+
Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
|
|
9
|
+
|
|
10
|
+
| Provider | Access | Scopes | Check command |
|
|
11
|
+
|---|---|---|---|
|
|
12
|
+
| Pendo | `app.pendo.io → x-pendo-integration-key: <SECRET>`. The EU region is `app.eu.pendo.io` | A read-only integration key | `curl -fsS https://app.pendo.io/api/v1/page -H 'Content-Type: application/json'` (check the vendor page) |
|
|
13
|
+
| Mixpanel | `mixpanel.com → Authorization: Basic <service account user>:<SECRET>` | A service account with the Consumer role | `curl -fsS "https://mixpanel.com/api/app/me"` (check the vendor page) |
|
|
14
|
+
| Amplitude | `amplitude.com → Authorization: Basic <api key>:<SECRET>`, with the secret key as the Secret | The project's API key and secret key | `curl -fsS "https://amplitude.com/api/2/events/list"` (check the vendor page) |
|
|
15
|
+
| Google Analytics | Not released yet: its Data API takes short-lived OAuth tokens | The Viewer role, when it is released | Not released yet |
|
|
16
|
+
|
|
17
|
+
Token pages: Pendo **Settings › Integrations › Integration Keys**; Mixpanel **Organization Settings ›
|
|
18
|
+
Service Accounts**; Amplitude **Settings › Projects**.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# CI and CD
|
|
2
|
+
|
|
3
|
+
The agents read build results and logs to find why a check failed. Give access with a Secret the network edge
|
|
4
|
+
adds, or reuse the code host's access where the CI lives on the code host. Egress is open, so add only the
|
|
5
|
+
rule that adds the credential. Read access is enough for most work. The agent installs or uses whatever
|
|
6
|
+
client it prefers. The edge adds the credential to its requests.
|
|
7
|
+
|
|
8
|
+
Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
|
|
9
|
+
|
|
10
|
+
| Provider | Access | Scopes | Check command |
|
|
11
|
+
|---|---|---|---|
|
|
12
|
+
| GitHub Actions | The GitHub access of `code-repo.md`. A GitHub App connection adds `actions:read` to `install.permissions` | Actions: read | `curl -fsS "https://api.github.com/repos/<owner>/<name>/actions/runs?per_page=1"` |
|
|
13
|
+
| Azure Pipelines | The Azure DevOps access of `code-repo.md` | Build (Read) | `curl -fsS "https://dev.azure.com/<organization>/<project>/_apis/build/builds?api-version=7.1&\$top=1"` |
|
|
14
|
+
| Jenkins | `<jenkins host> → Authorization: Basic <user>:<SECRET>`, with the user's API token | A user with read access to the jobs | `curl -fsS https://<jenkins host>/api/json` |
|
|
15
|
+
| CircleCI | `circleci.com → Circle-Token: <SECRET>` | Personal API token | `curl -fsS https://circleci.com/api/v2/me` |
|
|
16
|
+
|
|
17
|
+
Token pages: Jenkins, the user's **Configure › API Token**; CircleCI **User Settings › Personal API Tokens**.
|
|
18
|
+
|
|
19
|
+
A Jenkins server inside the team's network is not on the internet. Hosted machines cannot reach it.
|
|
20
|
+
`../environment.md`, section 5, part C, says where the machines can run instead.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Cloud accounts
|
|
2
|
+
|
|
3
|
+
Cloud access is read-only: the agents read resources, logs and settings, and change nothing. The network
|
|
4
|
+
edge adds a credential as a header. The three cloud APIs below do not take a fixed key in a header: AWS signs
|
|
5
|
+
each request with its key, and Azure and Google Cloud take short-lived tokens. So the edge cannot add their
|
|
6
|
+
credentials today, and none of them is released yet. Egress is open, so a public endpoint is reachable with
|
|
7
|
+
no key.
|
|
8
|
+
|
|
9
|
+
Never put a cloud key in an env value, the setup script or the agent's instructions to work around this.
|
|
10
|
+
Every process on the machine reads them.
|
|
11
|
+
|
|
12
|
+
| Provider | Access | Scopes | Check command |
|
|
13
|
+
|---|---|---|---|
|
|
14
|
+
| AWS | Not released yet: each request is signed with the key | A read-only role, such as `ReadOnlyAccess`, when it is released | Not released yet |
|
|
15
|
+
| Azure | Not released yet: Entra tokens expire within hours | The Reader role, when it is released | Not released yet |
|
|
16
|
+
| Google Cloud | Not released yet: OAuth tokens expire within an hour | The Viewer role, when it is released | Not released yet |
|
|
17
|
+
|
|
18
|
+
Until it is released, the agent asks a person in the item for what it needs from the cloud, such as a log
|
|
19
|
+
excerpt.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Code hosts
|
|
2
|
+
|
|
3
|
+
Give access with a Secret the network edge adds, or with the provider's platform connection. Egress is open,
|
|
4
|
+
so add only the rule that adds the credential. Git over HTTPS and the REST API often take the token in
|
|
5
|
+
different forms: give each its own rule, scoped by host or by path. A connection also brings events, which
|
|
6
|
+
a `Trigger` turns into work. The agent installs or uses whatever git or API client it prefers. The edge adds
|
|
7
|
+
the credential to its requests.
|
|
8
|
+
|
|
9
|
+
Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
|
|
10
|
+
|
|
11
|
+
| Provider | Access | Scopes | Check command |
|
|
12
|
+
|---|---|---|---|
|
|
13
|
+
| GitHub | Platform connection `github` (the Orchestra GitHub App), with `.applyPreset(github.egressPolicy())`. Or a token: `api.github.com → Authorization: Bearer <SECRET>` and `github.com → Authorization: Basic x-access-token:<SECRET>` | Fine-grained token for the repository: Contents, Pull requests and Issues, read and write | `curl -fsS https://api.github.com/repos/<owner>/<name>` |
|
|
14
|
+
| Bitbucket Cloud | `api.bitbucket.org → Authorization: Bearer <SECRET>` and `bitbucket.org → Authorization: Basic x-bitbucket-api-token-auth:<SECRET>`. Platform connection `bitbucket` for events | API token with the repository and pull request read and write scopes | `curl -fsS https://api.bitbucket.org/2.0/repositories/<workspace>/<repository>` |
|
|
15
|
+
| GitLab | `gitlab.com`, paths `/api/*`, priority 310 → `PRIVATE-TOKEN: <SECRET>`, and `gitlab.com`, priority 300 → `Authorization: Basic oauth2:<SECRET>`. Platform connection `gitlab` for events | Personal or project access token with `api` | `curl -fsS https://gitlab.com/api/v4/projects/<url-encoded group/project>` |
|
|
16
|
+
| Azure DevOps | `dev.azure.com → Authorization: Basic pat:<SECRET>`, for the API and git. Platform connection `azure-devops` for events | Personal access token: Code (Read & write), and Work Items (Read & write) for Boards | `curl -fsS "https://dev.azure.com/<organization>/_apis/projects?api-version=7.1"` |
|
|
17
|
+
|
|
18
|
+
Token pages: GitHub `https://github.com/settings/personal-access-tokens`; Bitbucket
|
|
19
|
+
`https://id.atlassian.com/manage-profile/security/api-tokens`; GitLab **Settings › Access tokens** in the
|
|
20
|
+
project or the profile; Azure DevOps **User settings › Personal access tokens**.
|
|
21
|
+
|
|
22
|
+
## Git over HTTPS
|
|
23
|
+
|
|
24
|
+
Git sends Basic auth. The edge adds it, so the agent clones `https://<host>/<path>.git` with no user name
|
|
25
|
+
and no password in the address.
|
|
26
|
+
|
|
27
|
+
- **GitHub:** the user name is `x-access-token`, and the password is the token:
|
|
28
|
+
`SecretValue.basicAuth("x-access-token", SecretValue.fromEnv("ORCHESTRA_FDK_GITHUB_TOKEN"))`. The GitHub
|
|
29
|
+
App connection's preset adds git on `github.com` and `codeload.github.com` itself. Its `{ git: "read" }`
|
|
30
|
+
option gives clone and fetch, and no push.
|
|
31
|
+
- **Bitbucket:** the fixed user name `x-bitbucket-api-token-auth`. The Bitbucket connection adds its key on
|
|
32
|
+
`api.bitbucket.org` only, so git keeps this rule beside the connection.
|
|
33
|
+
- **GitLab:** the user name `oauth2`. The GitLab connection declares no git transport, so git keeps this
|
|
34
|
+
rule beside the connection.
|
|
35
|
+
- **Azure DevOps:** the user name is not checked, and the kit refuses an empty one, so use `pat`. One rule on
|
|
36
|
+
`dev.azure.com` serves the API and git.
|
|
37
|
+
|
|
38
|
+
## GitLab: two rules on one host
|
|
39
|
+
|
|
40
|
+
The API and git are both on `gitlab.com`. Two credentialed rules on one host at one priority are a tie, and
|
|
41
|
+
the first declared wins for every request. So scope the API rule to `paths: ["/api/*"]` and give it the higher
|
|
42
|
+
priority, 310. The git rule at 300 takes the rest of the host.
|
|
43
|
+
|
|
44
|
+
The API rule replaces the `PRIVATE-TOKEN` header. A project access token must be sent this way: sent as
|
|
45
|
+
`Authorization: Bearer` beside a placeholder `PRIVATE-TOKEN`, GitLab answers 401. A personal token works the
|
|
46
|
+
same way.
|
|
47
|
+
|
|
48
|
+
With the `gitlab` connection and `Auth.oauth()`, use `.allow(gitlab, { paths: ["/api/*"], priority: 310 })`
|
|
49
|
+
for the API instead, and keep the git rule. GitLab does not let the platform register the webhook. The
|
|
50
|
+
developer adds it in the project, under **Settings › Webhooks**, with the connection's address. Write the
|
|
51
|
+
address to a file the developer can read, and never print it:
|
|
52
|
+
`npx orchestra connections rotate-webhook-token gitlab --output-file <path>`. Each run makes a new address and
|
|
53
|
+
ends the old one. The platform's GitLab connection covers `gitlab.com` only.
|
|
54
|
+
|
|
55
|
+
## Connections and events
|
|
56
|
+
|
|
57
|
+
- **GitHub:** `Auth.githubApp()`. `install.permissions` adds to the default the platform gives
|
|
58
|
+
(`contents:read`, `metadata:read`, `pull_requests:write`), as `<permission>:<level>`, such as
|
|
59
|
+
`contents:write`. The apply prints an install link once. Give it to the developer only after they approved
|
|
60
|
+
the diff, and run the same apply again when the app is installed. Events: `PullRequest`, `Issues`,
|
|
61
|
+
`IssueComment`.
|
|
62
|
+
- **Bitbucket:** `Auth.customerManagedToken(<secret>)`, or `Auth.oauth()` once the organization registers
|
|
63
|
+
its own Bitbucket OAuth consumer. Install fields `workspace` and `repository`. The platform registers the
|
|
64
|
+
webhook. Run `orchestra connections list-event-types <connection>` for the events.
|
|
65
|
+
- **GitLab:** install field `projectPath` or `projectId`. Events: `Push`, `MergeRequestOpened`,
|
|
66
|
+
`MergeRequestUpdated`, `IssueOpened`, `IssueUpdated`, `NoteCreated`.
|
|
67
|
+
- **Azure DevOps:** `Auth.oauth()`: a Microsoft work account consents. Install fields `organization` and
|
|
68
|
+
`project`. `.allow(<connection>)` adds the key on `dev.azure.com` for the API. Git keeps the token rule,
|
|
69
|
+
scoped to `paths: ["*/info/refs", "*/git-upload-pack", "*/git-receive-pack"]` at priority 310, so the two
|
|
70
|
+
rules do not tie on one host. A path pattern that starts with `*` matches the end of the path only, so
|
|
71
|
+
a `*` in the middle of a pattern matches nothing. To allow clone and fetch without push, add
|
|
72
|
+
`.deny("azure-devops-no-push", { hosts: ["dev.azure.com"], paths: ["*/git-receive-pack"] })`. A deny at its
|
|
73
|
+
default priority, 900, wins over both rules. Leaving `*/git-receive-pack` out of the git rule does not stop
|
|
74
|
+
a push, because the connection's rule covers every path on the host. Or use a read-only token.
|
|
75
|
+
The platform registers the webhooks. The events fire for every repository in the project, so narrow a
|
|
76
|
+
trigger with `where`.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Databases
|
|
2
|
+
|
|
3
|
+
Use a staging database or a read replica only, through a read-only user. Never give the agents a production
|
|
4
|
+
database, and never a user that can write to production.
|
|
5
|
+
|
|
6
|
+
The network edge adds a credential to HTTPS requests only. A database's own protocol, such as PostgreSQL's,
|
|
7
|
+
carries the password inside its connection, where the edge cannot add it. A database reached over an HTTPS
|
|
8
|
+
API can take a Secret like any other service. Egress is open. The agent installs or uses whatever client it
|
|
9
|
+
prefers.
|
|
10
|
+
|
|
11
|
+
Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
|
|
12
|
+
|
|
13
|
+
| Provider | Access | Scopes | Check command |
|
|
14
|
+
|---|---|---|---|
|
|
15
|
+
| PostgreSQL, MySQL, SQL Server (their own protocol) | Not released yet: the password would sit on the machine | A read-only user on staging or a replica, when it is released | Not released yet |
|
|
16
|
+
| Supabase (a staging project) | `<project ref>.supabase.co → apikey: <SECRET>` and `Authorization: Bearer <SECRET>`, one Secret on two headers | The project's `anon` key, with row-level security on (check the vendor page) | `curl -fsS "https://<project ref>.supabase.co/rest/v1/<table>?limit=1"` |
|
|
17
|
+
|
|
18
|
+
For local work, the codebase's own local database, such as one from its compose file, needs no access: the
|
|
19
|
+
agent starts it on its machine (`../environment.md`).
|
|
20
|
+
|
|
21
|
+
Never put a database password in an env value, the setup script or the agent's instructions. Every process
|
|
22
|
+
on the machine reads them.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Package registries
|
|
2
|
+
|
|
3
|
+
Public registries need no access: egress is open. A private registry or feed needs a Secret the network edge
|
|
4
|
+
adds on the registry's host. Point the package manager at the registry's address with no user name and no
|
|
5
|
+
token in it: in `.npmrc`, `nuget.config`, `pip.conf` or an env value. The edge adds the credential. The agent
|
|
6
|
+
installs or uses whatever client it prefers.
|
|
7
|
+
|
|
8
|
+
Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
|
|
9
|
+
|
|
10
|
+
| Provider | Access | Scopes | Check command |
|
|
11
|
+
|---|---|---|---|
|
|
12
|
+
| npm, private registry (GitHub Packages, JFrog, Nexus) | `<registry host> → Authorization: Bearer <SECRET>` | Read packages | `curl -fsS https://<registry host>/<package name>` |
|
|
13
|
+
| PyPI, private index (JFrog, Nexus) | `<index host> → Authorization: Basic <user>:<SECRET>`. Ask which user name the index wants | Read packages | `curl -fsS https://<index host>/simple/<package name>/` |
|
|
14
|
+
| NuGet, Azure Artifacts | `pkgs.dev.azure.com → Authorization: Basic pat:<SECRET>` | Packaging (Read) | `curl -fsS "https://pkgs.dev.azure.com/<organization>/_packaging/<feed>/nuget/v3/index.json"` |
|
|
15
|
+
| NuGet, GitHub Packages | `nuget.pkg.github.com → Authorization: Basic <user>:<SECRET>` | `read:packages` | `curl -fsS https://nuget.pkg.github.com/<owner>/index.json` |
|
|
16
|
+
| Maven or Gradle, private repository | `<repository host> → Authorization: Basic <user>:<SECRET>` (check the vendor page) | Read packages | `curl -fsS https://<repository host>/<path to a known artifact>.pom` |
|
|
17
|
+
|
|
18
|
+
The public registries, such as `registry.npmjs.org`, `pypi.org`, `files.pythonhosted.org` and
|
|
19
|
+
`api.nuget.org`, need no rule.
|
|
20
|
+
|
|
21
|
+
## Never write the token on the machine
|
|
22
|
+
|
|
23
|
+
Never write the token into `.npmrc`, `pip.conf`, `nuget.config`, an env value or the setup script. Every
|
|
24
|
+
process on the machine reads them, and the setup script's output is kept. Keep the codebase's own file when it
|
|
25
|
+
holds the address only, for example:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
@<scope>:registry=https://<registry host>/
|
|
29
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Design
|
|
2
|
+
|
|
3
|
+
The agents read design files to build what the designer drew. Give access with a Secret the network edge adds,
|
|
4
|
+
with read scopes only. Egress is open, so add only the rule that adds the credential. The platform has no
|
|
5
|
+
design connection, so no design events reach the platform. The agent installs or uses whatever client it
|
|
6
|
+
prefers. The edge adds the credential to its requests.
|
|
7
|
+
|
|
8
|
+
Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
|
|
9
|
+
|
|
10
|
+
| Provider | Access | Scopes | Check command |
|
|
11
|
+
|---|---|---|---|
|
|
12
|
+
| Figma | `api.figma.com → X-Figma-Token: <SECRET>` | A personal access token with `file_content:read` | `curl -fsS "https://api.figma.com/v1/files/<file key>?depth=1"` |
|
|
13
|
+
|
|
14
|
+
Token page: Figma **Settings › Security › Personal access tokens**.
|
|
15
|
+
|
|
16
|
+
The file key is the part after `/design/` or `/file/` in the file's address.
|
|
17
|
+
|
|
18
|
+
The token sees every file its user can open. Make it for a user who sees only the team's files.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Feature flags
|
|
2
|
+
|
|
3
|
+
The agents read flag settings to see what each user gets, and turn a flag on only in a test environment.
|
|
4
|
+
Give access with a Secret the network edge adds, with read scopes, or write only on non-production
|
|
5
|
+
environments. Egress is open, so add only the rule that adds the credential. The agent installs or uses
|
|
6
|
+
whatever client it prefers. The edge adds the credential to its requests.
|
|
7
|
+
|
|
8
|
+
Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
|
|
9
|
+
|
|
10
|
+
| Provider | Access | Scopes | Check command |
|
|
11
|
+
|---|---|---|---|
|
|
12
|
+
| LaunchDarkly | `app.launchdarkly.com → Authorization: <SECRET>`, with no `Bearer` | An API access token with the Reader role | `curl -fsS https://app.launchdarkly.com/api/v2/projects` |
|
|
13
|
+
| Split | `api.split.io → Authorization: Bearer <SECRET>` | An Admin API key scoped to the test environments (check the vendor page) | `curl -fsS https://api.split.io/internal/api/v2/workspaces` |
|
|
14
|
+
| Unleash | `<unleash host> → Authorization: <SECRET>`, with no `Bearer` | A personal or service account token with read access | `curl -fsS https://<unleash host>/api/admin/projects` |
|
|
15
|
+
| ConfigCat | `api.configcat.com → Authorization: Basic <user>:<SECRET>` | Public API credentials | `curl -fsS https://api.configcat.com/v1/me` |
|
|
16
|
+
| Azure App Configuration | Not released yet: each request is signed with the key, or takes a short-lived Entra token | The App Configuration Data Reader role, when it is released | Not released yet |
|
|
17
|
+
|
|
18
|
+
Token pages: LaunchDarkly **Organization settings › Authorization**; Split **Admin settings › API keys**;
|
|
19
|
+
Unleash **Admin › API access**; ConfigCat **Public API credentials**.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Incidents
|
|
2
|
+
|
|
3
|
+
The agents read incidents and their timelines to find what broke. Give access with a Secret the network edge
|
|
4
|
+
adds, with read scopes only. Egress is open, so add only the rule that adds the credential. The platform has
|
|
5
|
+
no incident connection, so no incident events reach the platform. The agent installs or uses whatever client
|
|
6
|
+
it prefers. The edge adds the credential to its requests.
|
|
7
|
+
|
|
8
|
+
Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
|
|
9
|
+
|
|
10
|
+
| Provider | Access | Scopes | Check command |
|
|
11
|
+
|---|---|---|---|
|
|
12
|
+
| PagerDuty | `api.pagerduty.com → Authorization: Token token=<SECRET>` | A read-only REST API key | `curl -fsS https://api.pagerduty.com/abilities -H 'Accept: application/vnd.pagerduty+json;version=2'` |
|
|
13
|
+
| Opsgenie | `api.opsgenie.com → Authorization: GenieKey <SECRET>`. The EU region is `api.eu.opsgenie.com` | An API key with Read access | `curl -fsS https://api.opsgenie.com/v2/account` |
|
|
14
|
+
|
|
15
|
+
Token pages: PagerDuty **Integrations › API Access Keys**; Opsgenie **Settings › API key management**.
|
|
16
|
+
|
|
17
|
+
## A header with its own word
|
|
18
|
+
|
|
19
|
+
Both put a word of their own before the key, so neither is `Bearer` nor `Basic`. Bind them with `inject`:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
.allow("pagerduty", {
|
|
23
|
+
hosts: ["api.pagerduty.com"],
|
|
24
|
+
priority: 300,
|
|
25
|
+
credential: inject(pagerduty, { headers: [{ name: "authorization", value: "Token token=${secret}" }] }),
|
|
26
|
+
})
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
For Opsgenie, the value is `GenieKey ${secret}`.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Trackers
|
|
2
|
+
|
|
3
|
+
Give access with a Secret the network edge adds, or with the tracker's platform connection. Egress is open,
|
|
4
|
+
so add only the rule that adds the credential. A connection also brings events: a `Trigger` on them makes a
|
|
5
|
+
work item for each new issue. The agent installs or uses whatever client it prefers. The edge adds the
|
|
6
|
+
credential to its requests.
|
|
7
|
+
|
|
8
|
+
Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
|
|
9
|
+
|
|
10
|
+
| Provider | Access | Scopes | Check command |
|
|
11
|
+
|---|---|---|---|
|
|
12
|
+
| Jira Cloud, API token | `<site>.atlassian.net → Authorization: Basic <email>:<SECRET>` | API token without scopes | `curl -fsS https://<site>.atlassian.net/rest/api/3/myself` |
|
|
13
|
+
| Jira Cloud, `jira` | Platform connection `jira` (the Orchestra app for Jira), with `.applyPreset(jira.egressPolicy())` | Set by the app | `curl -fsS https://api.atlassian.com/ex/jira/<cloudId>/rest/api/3/myself` |
|
|
14
|
+
| Jira Cloud, `jira-classic` | Platform connection `jira-classic`, with `.allow(jiraClassic)` on `api.atlassian.com` | Set by the consent | `curl -fsS https://api.atlassian.com/ex/jira/<cloudId>/rest/api/3/myself` |
|
|
15
|
+
| Linear | `api.linear.app → Authorization: <SECRET>`, with no `Bearer`. Or platform connection `linear` | Personal API key | `curl -fsS https://api.linear.app/graphql -H 'Content-Type: application/json' -d '{"query":"{ viewer { id } }"}'` |
|
|
16
|
+
| GitHub Issues | The GitHub access of `code-repo.md`, with Issues read and write | Issues: read and write | `curl -fsS "https://api.github.com/repos/<owner>/<name>/issues?per_page=1"` |
|
|
17
|
+
| Azure Boards | The Azure DevOps access of `code-repo.md` | Work Items (Read & write) | `curl -fsS "https://dev.azure.com/<organization>/<project>/_apis/wit/workitems?ids=<id>&api-version=7.1"` |
|
|
18
|
+
|
|
19
|
+
Token pages: Jira `https://id.atlassian.com/manage-profile/security/api-tokens`; Linear **Settings › Account ›
|
|
20
|
+
Security & access**.
|
|
21
|
+
|
|
22
|
+
## Jira: three routes
|
|
23
|
+
|
|
24
|
+
- **API token.** Basic auth over the account email and the token: `SecretValue.basicAuth("<email>",
|
|
25
|
+
SecretValue.fromEnv("<VAR>"))`. Make the token without scopes: a token with scopes
|
|
26
|
+
works only through `api.atlassian.com`, and this rule adds it on the site host. The site host, such as
|
|
27
|
+
`acme.atlassian.net`, is an env value or a constant in the code. No events.
|
|
28
|
+
- **`jira`, the Orchestra app for Jira.** `Auth.forgeApp()`, install field `siteUrl`. A Jira admin installs
|
|
29
|
+
the app from the connection's `auth.authorizationUrl` (`npx orchestra connections get jira --output json`).
|
|
30
|
+
The connection turns `ACTIVE` at the first event from the site. The app's key works only on
|
|
31
|
+
`api.atlassian.com`. Grant it with `.applyPreset(jira.egressPolicy())`: the preset adds the key on
|
|
32
|
+
`api.atlassian.com` only, and opens the site host with no key. A plain `.allow(jira)` would add the key on
|
|
33
|
+
both. Events: `CreatedIssue`, `UpdatedIssue`, `DeletedIssue`, `CommentedIssue`. The field `selfGenerated`
|
|
34
|
+
is true on a change the app made: filter it out with `where`.
|
|
35
|
+
- **`jira-classic`.** Install field `projectKey`. `Auth.oauth()`: the apply prints no link for it. Read
|
|
36
|
+
`auth.authorizationUrl` from `npx orchestra connections get <slug> --output json`, the developer consents,
|
|
37
|
+
and you apply again. The platform registers the webhook. Grant the key with
|
|
38
|
+
`.allow(jiraClassic)`, which adds it on `api.atlassian.com`. Events: `IssueCreated`, `IssueUpdated`,
|
|
39
|
+
`IssueDeleted`, `CommentCreated`.
|
|
40
|
+
|
|
41
|
+
A connection keeps its credential apart from the network rules. Without the grant on an environment, the
|
|
42
|
+
agents on it reach Jira with no key.
|
|
43
|
+
|
|
44
|
+
## GitHub Issues: one item per issue
|
|
45
|
+
|
|
46
|
+
A trigger that makes one work item per issue keys it with a `binding`. Issue numbers repeat across
|
|
47
|
+
repositories, so key on GitHub's global issue id, or put the repository in the key:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
binding: binding`${context.connection.slug}:${context.event.payload("repository.full_name")}:${context.event.payload("issue.number")}`
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
A comment on a pull request also arrives as `IssueComment`: filter it out with
|
|
54
|
+
`field("issue.pull_request").isAbsent()`.
|
|
55
|
+
|
|
56
|
+
## Linear
|
|
57
|
+
|
|
58
|
+
The key goes bare in the `Authorization` header: `header("Authorization", secret)`. With the `linear`
|
|
59
|
+
connection, `Auth.customerManagedToken(<secret>)` or `Auth.oauth()`, and `.allow(linear)` adds its key. The
|
|
60
|
+
platform registers the webhook. Events: `IssueCreate`, `IssueUpdate`, `IssueRemove`, `CommentCreate`.
|
|
61
|
+
|
|
62
|
+
## Azure Boards
|
|
63
|
+
|
|
64
|
+
A work item comment arrives as `WorkitemUpdated`, with its text at
|
|
65
|
+
`resource.fields["System.History"].newValue`. There is no separate comment event.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Knowledge bases
|
|
2
|
+
|
|
3
|
+
Give access with a Secret the network edge adds, or with the provider's platform connection. Egress is open,
|
|
4
|
+
so add only the rule that adds the credential. The agent installs or uses whatever client it prefers. The
|
|
5
|
+
edge adds the credential to its requests.
|
|
6
|
+
|
|
7
|
+
Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
|
|
8
|
+
|
|
9
|
+
| Provider | Access | Scopes | Check command |
|
|
10
|
+
|---|---|---|---|
|
|
11
|
+
| Notion | `api.notion.com → Authorization: Bearer <SECRET>`. Or platform connection `notion`, with `.allow(notion)` | An internal integration, shared with each page or database the agents need | `curl -fsS https://api.notion.com/v1/users/me -H 'Notion-Version: 2022-06-28'` |
|
|
12
|
+
| Confluence Cloud | `<site>.atlassian.net → Authorization: Basic <email>:<SECRET>` | API token without scopes | `curl -fsS "https://<site>.atlassian.net/wiki/api/v2/spaces?limit=1"` |
|
|
13
|
+
| Guru | `api.getguru.com → Authorization: Basic <email>:<SECRET>`. Or platform connection `guru` (OAuth, read only), with `.allow(guru)` | User API token | `curl -fsS https://api.getguru.com/api/v1/whoami` (check the vendor page) |
|
|
14
|
+
|
|
15
|
+
Token pages: Notion `https://www.notion.so/profile/integrations`; Confluence
|
|
16
|
+
`https://id.atlassian.com/manage-profile/security/api-tokens`; Guru, the user's API tokens in Guru's
|
|
17
|
+
settings.
|
|
18
|
+
|
|
19
|
+
## Notion
|
|
20
|
+
|
|
21
|
+
The integration sees only the pages and databases the developer shares with it in Notion. Each Notion API
|
|
22
|
+
call also needs a `Notion-Version` header, which the agent's client sends itself.
|
|
23
|
+
|
|
24
|
+
The `notion` connection takes `Auth.customerManagedToken(<secret>)` or `Auth.oauth()`, install fields
|
|
25
|
+
`workspaceId` and `workspaceUrl`, both optional. Its events are `PageCreated` and `PageContentUpdated`.
|
|
26
|
+
The platform does not register the webhook. The developer adds it by hand in the integration's settings in
|
|
27
|
+
Notion, with the connection's address. Write the address to a file the developer can read, and never print
|
|
28
|
+
it: `npx orchestra connections rotate-webhook-token notion --output-file <path>`. Each run makes a new
|
|
29
|
+
address and ends the old one.
|
|
30
|
+
|
|
31
|
+
## Confluence
|
|
32
|
+
|
|
33
|
+
Basic auth over the account email and the token, on the site host. Make the token without scopes, for the
|
|
34
|
+
same reason as Jira's (`issue-tracker.md`). When the team uses a Jira API token on the same site with the
|
|
35
|
+
same account, reuse that Secret and its rule: one rule on the site host serves both. The platform has no
|
|
36
|
+
Confluence connection, so Confluence sends no events.
|
|
37
|
+
|
|
38
|
+
## Guru
|
|
39
|
+
|
|
40
|
+
The `guru` connection asks Guru for read access with `Auth.oauth()`. The apply prints no link for it: read
|
|
41
|
+
`auth.authorizationUrl` from `npx orchestra connections get <slug> --output json`, the developer consents, and
|
|
42
|
+
you apply again. The platform registers the webhook. Events: `CardCreated`,
|
|
43
|
+
`CardUpdated`, `CardDeleted`.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Chat
|
|
2
|
+
|
|
3
|
+
Slack and Microsoft Teams take no personal token here. Access is the platform connection only: the developer
|
|
4
|
+
or a tenant admin approves the app in the browser, and the network edge adds the app's key to the agent's
|
|
5
|
+
replies. Egress is open, so the connection's own rule, `.allow(<connection>)`, is the only rule to add. The
|
|
6
|
+
agent installs or uses whatever client it prefers. The edge adds the key to its requests.
|
|
7
|
+
|
|
8
|
+
| Provider | Access | Scopes | Check command |
|
|
9
|
+
|---|---|---|---|
|
|
10
|
+
| Slack | Platform connection `slack` (the Orchestra Slack app), `Auth.oauth()`, with `.allow(slack)` on `slack.com` | Set by the app | `curl -sS -X POST https://slack.com/api/auth.test`. Passes only when the answer holds `"ok":true`: Slack answers `200` with `"ok":false` when no key was added |
|
|
11
|
+
| Microsoft Teams | Platform connection `teams` (the Orchestra bot), `Auth.oauth()`, with `.allow(teams)` | Set by the app; a tenant admin consents | The agent sends one message with its own choice of tool, on a conversation where the bot has seen a message. Passes only when the answer carries the new message's `id` and the message shows in Teams |
|
|
12
|
+
|
|
13
|
+
## OAuth only
|
|
14
|
+
|
|
15
|
+
Both apps sign in with OAuth, and the platform fills the install fields, so `install` stays empty. The apply
|
|
16
|
+
prints `connection '<slug>' needs attention — authorize at: <link>`. For Slack, the developer opens it and
|
|
17
|
+
adds the app to the workspace. For Teams, the consent is for the whole Microsoft tenant, so a tenant admin
|
|
18
|
+
must open it. Then run the same apply again.
|
|
19
|
+
|
|
20
|
+
Without `.allow(<connection>)` on the agent's environment, a reply is refused at the network edge, and synth
|
|
21
|
+
prints a warning.
|
|
22
|
+
|
|
23
|
+
## Conversations
|
|
24
|
+
|
|
25
|
+
`Providers.Slack.conversation` and `Providers.Teams.conversation` give the events and the bindings for a
|
|
26
|
+
trigger that starts or wakes an agent's conversation: Slack's `mention`, `dm`, `groupChat` and `threadReply`;
|
|
27
|
+
Teams' `message`, split by `inChannel()`, `inDirectMessage()` and `inGroupChat()`. Both have
|
|
28
|
+
`sessionPerThread()`, `sessionPerConversation()` and `rooms([...])`. Set `attributeConnection: true` on the
|
|
29
|
+
trigger's agent target. `autoRespond` on the connection sets what the app shows on each message: Slack takes
|
|
30
|
+
a reaction, a typing status and a failure notice; Teams takes `typing` and `failureNotice`.
|
|
31
|
+
|
|
32
|
+
The agent replies through the provider's own API: Slack's Web API on `slack.com`, and the Bot Framework for
|
|
33
|
+
Teams. On Teams, the edge adds the bot's key only for a conversation where the bot has already seen a
|
|
34
|
+
message.
|
|
35
|
+
|
|
36
|
+
**Not built yet:** acting as the person who wrote the message (the agent speaks as the app), starting a Teams
|
|
37
|
+
conversation where the bot has not been seen, and dropping the app's own messages before the agent sees
|
|
38
|
+
them.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Observability
|
|
2
|
+
|
|
3
|
+
The agents read errors, traces and metrics to find the cause of a bug. Give access with a Secret the network
|
|
4
|
+
edge adds, with read scopes only. Egress is open, so add only the rule that adds the credential. None of these
|
|
5
|
+
has a platform connection, so none sends events to the platform. The agent installs or uses whatever client
|
|
6
|
+
it prefers. The edge adds the credential to its requests.
|
|
7
|
+
|
|
8
|
+
Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
|
|
9
|
+
|
|
10
|
+
| Provider | Access | Scopes | Check command |
|
|
11
|
+
|---|---|---|---|
|
|
12
|
+
| Sentry | `sentry.io → Authorization: Bearer <SECRET>`. The EU region is `de.sentry.io`; a self-hosted Sentry uses its own host | `project:read`, `event:read` | `curl -fsS https://sentry.io/api/0/organizations/` |
|
|
13
|
+
| Datadog | `api.datadoghq.com → DD-API-KEY: <SECRET>` and `DD-APPLICATION-KEY: <SECRET>`, two Secrets on one rule. Other sites use their own host, such as `api.datadoghq.eu` | An application key with read scopes | `curl -fsS https://api.datadoghq.com/api/v1/validate` |
|
|
14
|
+
| New Relic | `api.newrelic.com → API-Key: <SECRET>`. The EU region is `api.eu.newrelic.com` | A user key | `curl -fsS https://api.newrelic.com/graphql -H 'Content-Type: application/json' -d '{"query":"{ actor { user { email } } }"}'` |
|
|
15
|
+
| Grafana Cloud | `<stack>.grafana.net → Authorization: Bearer <SECRET>` | A service account token with the Viewer role | `curl -fsS "https://<stack>.grafana.net/api/search?limit=1"` |
|
|
16
|
+
| Application Insights | `api.applicationinsights.io → x-api-key: <SECRET>` (check the vendor page: Microsoft is moving this API to Entra sign-in) | Read telemetry | `curl -fsS "https://api.applicationinsights.io/v1/apps/<app id>/metadata"` |
|
|
17
|
+
| CloudWatch | Not released yet. AWS signs each request with its key, so the edge cannot add it as a header | Not released yet | Not released yet |
|
|
18
|
+
|
|
19
|
+
Token pages: Sentry **Settings › Auth Tokens**; Datadog **Organization Settings › API Keys** and
|
|
20
|
+
**Application Keys**; New Relic **API keys**; Grafana **Administration › Service accounts**.
|
|
21
|
+
|
|
22
|
+
## Datadog: two headers
|
|
23
|
+
|
|
24
|
+
Datadog wants two keys on each API call: the organization's API key and a user's application key. Store each
|
|
25
|
+
as its own Secret, and add both on one rule:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
.allow("datadog", {
|
|
29
|
+
hosts: ["api.datadoghq.com"],
|
|
30
|
+
priority: 300,
|
|
31
|
+
credentials: [header("DD-API-KEY", datadogApiKey), header("DD-APPLICATION-KEY", datadogAppKey)],
|
|
32
|
+
})
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The application key carries the user's rights. Make it for a user, or a service account, with read access
|
|
36
|
+
only.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Secrets managers
|
|
2
|
+
|
|
3
|
+
A secrets manager is a source for the factory's Secrets, not a service the agents call. The developer reads
|
|
4
|
+
each token from the manager into the shell of the apply, on their own computer. The apply stores it as an
|
|
5
|
+
Orchestra Secret, and the network edge adds it. The value is never printed, never in the chat, and never on
|
|
6
|
+
a machine.
|
|
7
|
+
|
|
8
|
+
| Provider | Access | Scopes | Check command |
|
|
9
|
+
|---|---|---|---|
|
|
10
|
+
| 1Password | On the developer's computer: `ORCHESTRA_FDK_<NAME>_TOKEN=$(op read "op://<vault>/<item>/<field>")` in the apply's shell | Read on the vault | `op whoami` |
|
|
11
|
+
| HashiCorp Vault | On the developer's computer: `ORCHESTRA_FDK_<NAME>_TOKEN=$(vault kv get -field=<field> <path>)` in the apply's shell | A policy with `read` on the path | `vault token lookup` |
|
|
12
|
+
| Azure Key Vault | On the developer's computer: `ORCHESTRA_FDK_<NAME>_TOKEN=$(az keyvault secret show --vault-name <vault> --name <name> --query value -o tsv)` in the apply's shell | The Key Vault Secrets User role | `az account show` |
|
|
13
|
+
|
|
14
|
+
The check commands run on the developer's computer, with their own sign-in to the manager.
|
|
15
|
+
|
|
16
|
+
## How the value travels
|
|
17
|
+
|
|
18
|
+
1. The developer exports the variable in the shell that runs the apply. You run the apply in that shell
|
|
19
|
+
only when the developer can export it there. Otherwise the developer writes the value into the private
|
|
20
|
+
token file (phase 2, "The private token file") from the manager.
|
|
21
|
+
2. The factory reads it with `SecretValue.fromEnv("ORCHESTRA_FDK_<NAME>_TOKEN")`.
|
|
22
|
+
3. Never echo the variable, and never pass the value as a command argument: both can reach a log.
|
|
23
|
+
|
|
24
|
+
A Secret keeps the value it had at its last apply. After the developer rotates a token in the manager, apply
|
|
25
|
+
again with the new value loaded.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Support desks
|
|
2
|
+
|
|
3
|
+
Give access with a Secret the network edge adds, or with the provider's platform connection. Egress is open,
|
|
4
|
+
so add only the rule that adds the credential. A connection also brings events: a `Trigger` on them makes a
|
|
5
|
+
work item in the Support pipeline for each new ticket. The agent installs or uses whatever client it prefers.
|
|
6
|
+
The edge adds the credential to its requests.
|
|
7
|
+
|
|
8
|
+
Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
|
|
9
|
+
|
|
10
|
+
| Provider | Access | Scopes | Check command |
|
|
11
|
+
|---|---|---|---|
|
|
12
|
+
| Zendesk | Platform connection `zendesk`, install field `subdomain`, with `.allow(zendesk)` on `<subdomain>.zendesk.com`. Or a token: `<subdomain>.zendesk.com → Authorization: Basic <email>/token:<SECRET>` | An agent's API token | `curl -fsS https://<subdomain>.zendesk.com/api/v2/users/me.json` |
|
|
13
|
+
| Intercom | Platform connection `intercom`, with `.allow(intercom)` on `api.intercom.io`. Or a token: `api.intercom.io → Authorization: Bearer <SECRET>` | An access token from a private app | `curl -fsS https://api.intercom.io/me` |
|
|
14
|
+
| Freshdesk | `<domain>.freshdesk.com → Authorization: Basic <SECRET>:X`. The API key is the user name, and `X` is the password | An agent's API key | `curl -fsS https://<domain>.freshdesk.com/api/v2/agents/me` |
|
|
15
|
+
|
|
16
|
+
Token pages: Zendesk **Admin Center › Apps and integrations › APIs**; Intercom **Developer Hub**; Freshdesk
|
|
17
|
+
**Profile settings › API key**.
|
|
18
|
+
|
|
19
|
+
## Basic auth with a fixed suffix
|
|
20
|
+
|
|
21
|
+
- **Zendesk:** the user name is the agent's email followed by `/token`, and the password is the token:
|
|
22
|
+
`SecretValue.basicAuth("<email>/token", SecretValue.fromEnv("ORCHESTRA_FDK_ZENDESK_TOKEN"))`.
|
|
23
|
+
- **Freshdesk:** the API key is the user name, and the password is any fixed text, such as `X`. The kit's
|
|
24
|
+
Basic recipe puts the Secret in the password, so store the whole `<api key>:X` pair, base64-encoded, as the
|
|
25
|
+
Secret's value, and bind it with `basic("Authorization", secret)` (check the vendor page).
|
|
26
|
+
|
|
27
|
+
## Events
|
|
28
|
+
|
|
29
|
+
Each connection's events: `orchestra connections list-event-types <connection>`. The Intercom webhook is set
|
|
30
|
+
up by hand in Intercom's Developer Hub, with the connection's address. Write the address to a file the
|
|
31
|
+
developer can read: `npx orchestra connections rotate-webhook-token <connection> --output-file <path>`.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Phase 0: Start
|
|
2
|
+
|
|
3
|
+
**Goal:** the kit is installed and current, you are signed in to the organization the developer chose, and
|
|
4
|
+
you know what the platform can do.
|
|
5
|
+
|
|
6
|
+
## 1. Install the kit
|
|
7
|
+
|
|
8
|
+
The kit is the `orchestra` command and the library the factory code imports. It was installed before this
|
|
9
|
+
skill was linked, in one of two places. Keep it and its skills current with the command that matches:
|
|
10
|
+
|
|
11
|
+
- Globally, with `npm install -g @orchestraworks/cli`. Update it with `npm update -g @orchestraworks/cli`.
|
|
12
|
+
Then `orchestra` runs in any folder.
|
|
13
|
+
- In the factory folder, with `npm install @orchestraworks/cli` there. Update it with
|
|
14
|
+
`npm update @orchestraworks/cli`, run in that folder. Run the command there as `npx orchestra`.
|
|
15
|
+
|
|
16
|
+
Use one way to run the command in each place:
|
|
17
|
+
|
|
18
|
+
- Where no factory folder with the kit exists yet (phases 0 to 3), run
|
|
19
|
+
`npx --package @orchestraworks/cli orchestra`. With a global install, plain `orchestra` works too.
|
|
20
|
+
- In a factory folder after its `npm install`, run `npx orchestra`.
|
|
21
|
+
|
|
22
|
+
Find the developer's codebase folder. Call it `<codebase>`. Then run
|
|
23
|
+
`npx --package @orchestraworks/cli orchestra --help`. It prints the command list. Node 22 or later is needed.
|
|
24
|
+
|
|
25
|
+
## 2. Sign in
|
|
26
|
+
|
|
27
|
+
1. Tell the developer: "A browser window will open. Sign in to Orchestra there and confirm."
|
|
28
|
+
2. Run the sign-in with a command timeout of at least five minutes. The CLI opens the browser and waits for
|
|
29
|
+
the answer on a local port of this computer, so the browser must run on this same computer. When the
|
|
30
|
+
developer belongs to one organization, the login selects it. When they belong to several, the login stops
|
|
31
|
+
and asks you to name one. Ask the developer which, then run:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx --package @orchestraworks/cli orchestra auth login --org <organization>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
This sign-in renews itself, so a long run stays signed in. The address it signs in to is its first line.
|
|
38
|
+
3. Use this browser sign-in. `orchestra auth login --no-browser` asks for a token at a hidden prompt
|
|
39
|
+
instead, and a typed token cannot renew itself: it stops working when it expires. Use it only for a short
|
|
40
|
+
run, with a token someone hands the developer. Users cannot create their own API keys in the console
|
|
41
|
+
yet; that is coming. If no browser can open on this computer, tell the developer. Ask them to run you on
|
|
42
|
+
a computer where one can.
|
|
43
|
+
4. Read the two lines the login prints: `Signed in as <email>.` and
|
|
44
|
+
`Logged in to organization <id> (<slug>).` Tell the developer both, and confirm the organization.
|
|
45
|
+
|
|
46
|
+
## 3. Read the orchestra skill
|
|
47
|
+
|
|
48
|
+
Read `orchestra/SKILL.md` in your skill folder, in full, before phase 1. It says what each idea is for, what
|
|
49
|
+
the starter declares, and what the platform cannot do yet. The later phases point at its sections. Never
|
|
50
|
+
promise one of its "Cannot yet" lines.
|
|
51
|
+
|
|
52
|
+
## Exit check
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npx --package @orchestraworks/cli orchestra me get --output json
|
|
56
|
+
node -p 'require(require("os").homedir() + "/.config/orchestra/config.json").profiles.default.organizationId'
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The first answer's `email` is the developer's. A signed-in person's answer names no organization, so the
|
|
60
|
+
second command reads the organization from the profile the sign-in saved. It prints only that id, never the
|
|
61
|
+
token. The id is the one in `Logged in to organization <id> (<slug>).`, which the developer confirmed. You
|
|
62
|
+
have read the orchestra skill. If the check fails, read `../troubleshooting.md`, "The sign-in stops working".
|