From ca64fb76963fb287ed8b45a9d07bb0fe8dd5d748 Mon Sep 17 00:00:00 2001 From: AaronPlave Date: Fri, 20 Feb 2026 09:56:36 -0800 Subject: [PATCH 1/6] Action secrets/credentials docs and upgrade guide --- docs/sequencing/actions.mdx | 137 +++++++++++++++++--------- docs/upgrade-guides/4-0-0-to-4-1-0.md | 43 ++++++++ sidebars.js | 1 + 3 files changed, 137 insertions(+), 44 deletions(-) create mode 100644 docs/upgrade-guides/4-0-0-to-4-1-0.md diff --git a/docs/sequencing/actions.mdx b/docs/sequencing/actions.mdx index 75a2f2e..dfcafbf 100644 --- a/docs/sequencing/actions.mdx +++ b/docs/sequencing/actions.mdx @@ -1,22 +1,22 @@ # SeqDev Actions :::danger -Actions are a new *experimental feature* as of PlanDev v3.4.0, and not yet recommended for use in production environments. +Actions are a new _experimental feature_ as of PlanDev v3.4.0, and not yet recommended for use in production environments. Development is active, and the API may be subject to further change. Please let us know if you have feedback on their future development! ::: -Actions are *custom tasks* that developers can write and upload to a SeqDev Sequencing **workspace**, in order to -traceably automate operations on the sequences and files within the workspace. Actions may *read from* and *write to* the contents of the +Actions are _custom tasks_ that developers can write and upload to a SeqDev Sequencing **workspace**, in order to +traceably automate operations on the sequences and files within the workspace. Actions may _read from_ and _write to_ the contents of the workspace, and may communicate with other services to provide things such as translation, static checking or compilation. More info about this decision and its intentions can be found in [ADR-0101 - SeqDev Actions](/overview/design/arch-decision-records/adr-0101-seqdev-actions). -This document describes the *current state* of the Actions feature as it exists today. Check the roadmap section at the +This document describes the _current state_ of the Actions feature as it exists today. Check the roadmap section at the end to understand how it may change in the future. ## Using Actions -This section demonstrates how to use Actions in the UI and assumes you *already have* an action file to use - you can download +This section demonstrates how to use Actions in the UI and assumes you _already have_ an action file to use - you can download [this demo action](/assets/action.js) to use as an example, or follow instructions in the "Writing an Action" section below to build your own. @@ -29,12 +29,13 @@ runs of those actions - currently both empty lists. Once you're on the Actions page, click "New Action", give it a name ('test-action') and upload the `action.js` file for your action (the provided example, or the output of your build step). If this completes successfully, you should see your new action appear in the list on the left side of the page. Click on the row to see details about your action: -- The **Runs** tab shows you all past runs of *this* action, currently none -- The **Configure** tab gives you access to the *settings values* for your action. These are configuration settings defined by the action, which can be modified and saved to be used in subsequent runs. + +- The **Runs** tab shows you all past runs of _this_ action, currently none +- The **Configure** tab gives you access to the _settings values_ for your action. These are configuration settings defined by the action, which can be modified and saved to be used in subsequent runs. - The **Code** tab shows you the (compiled) source code of your action, ie. the contents of `action.js` -*The rest of these instructions will assume you're using the example action - modify them as needed for your own -settings/parameters.* The example action attempts to **make a request** to an external URL and return the response as its +_The rest of these instructions will assume you're using the example action - modify them as needed for your own +settings/parameters._ The example action attempts to **make a request** to an external URL and return the response as its result. Go to the "Configure" page and, for the setting called "externalURL", enter `https://api.github.com`. This will be used as the **base URL** for requests made by this action. Click Save to save your settings. @@ -54,7 +55,6 @@ Finally, you can go back to the main Actions page for your workspace, which shou list and gives you access to the list of all past runs, for purposes of traceability. Each run saves the settings and parameters used for the run, as well as any results, logs and errors encountered during the run. - ## Writing an Action Actions must be written in **Javascript or Typescript**, though other languages may be supported in the future. If you're @@ -63,15 +63,15 @@ unfamiliar with working on JS projects, it's a good idea to use an IDE such as [ We provide two resources for developers who want to write a new action: -* **[aerie-action-template](https://github.com/NASA-AMMOS/aerie-action-template)**, a boilerplate template showing the structure of an action -* The **[aerie-actions](https://github.com/NASA-AMMOS/aerie-actions)** JS package, a library of utilities used by actions +- **[aerie-action-template](https://github.com/NASA-AMMOS/aerie-action-template)**, a boilerplate template showing the structure of an action +- The **[aerie-actions](https://github.com/NASA-AMMOS/aerie-actions)** JS package, a library of utilities used by actions We recommend starting a new action by forking or copying the **[aerie-action-template](https://github.com/NASA-AMMOS/aerie-action-template)** repository and using it as a starting point. Once you have a local copy, `cd` to it and run the following commands: -* `nvm use` - (optional, but ensures you're using the correct `node` version. You may have to [install NVM](https://github.com/nvm-sh/nvm) first) -* `npm install` to install dependencies -* `npm run build` to make sure you are setup correctly to build +- `nvm use` - (optional, but ensures you're using the correct `node` version. You may have to [install NVM](https://github.com/nvm-sh/nvm) first) +- `npm install` to install dependencies +- `npm run build` to make sure you are setup correctly to build Files in the `/dist` folder are generated and should not be modified directly - the action's source files are in the `/src` directory. Open [`src/index.ts`](https://github.com/NASA-AMMOS/aerie-action-template/blob/main/src/index.ts) in @@ -81,8 +81,8 @@ from `aerie-actions`, which we'll discuss below. ### Action parameters and settings Actions may define two types of configuration which may be provided by the user to affect the action's behavior: -**parameters** and **settings**. In both cases, the action developer defines the *names* and *types* of expected parameters/settings -in the action code, and the user may provide *values* for them at runtime. The difference between them is that +**parameters** and **settings**. In both cases, the action developer defines the _names_ and _types_ of expected parameters/settings +in the action code, and the user may provide _values_ for them at runtime. The difference between them is that the values of **settings** are saved in the database and used in subsequent runs - to be used for persistent configuration such as the URL of a service which does not change often - while **parameter** values are expected to be provided by the user on every run of the action. @@ -90,21 +90,24 @@ by the user on every run of the action. You must define your parameters and settings as shown in the template structure: the variables **must** be called `parameterDefinitions` and `settingDefinitions`, but you should replace the contents with your desired parameter/setting names and their types. For example, the code: + ``` export const parameterDefinitions = { myName: { type: "string" }, myAge: { type: "int" } } satisfies ActionParameterDefinitions; ``` + defines two user-provided parameters, a string called `myName` and an integer called `myAge`. The full list of supported types can be found in the [aerie-actions value schema definition](https://github.com/NASA-AMMOS/aerie-actions/blob/main/src/types/schema.ts). If you are using Typescript, the next two lines should be left alone: + ``` type MyActionParameters = ActionParameters; type MyActionSettings = ActionSettings; ``` -as these will ensure that your function is provided with correct TS types for the parameters & settings you defined. +as these will ensure that your function is provided with correct TS types for the parameters & settings you defined. ### The action `main` function @@ -112,19 +115,18 @@ Every action is expected to export a function called **`main`**, containing the when the action is invoked: ```js -export async function main( - parameters: MyActionParameters, - settings: MyActionSettings, - actionsAPI: ActionsAPI -) { /* action code here ... */ } +export async function main(parameters: MyActionParameters, settings: MyActionSettings, actionsAPI: ActionsAPI) { + /* action code here ... */ +} ``` Actions are expected to by asynchronous, potentially long-running tasks - therefore `main` is expected to be an `async` function, or a function which returns a [`Promise` which is `resolve`d](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) when the action is done running. -* The first argument to `main` is `parameters` - the user-provided parameter values for this run, which will match the structure of your `parameterDefinitions` -* The second argument is `settings` - the user-provided setting values, matching structure of `settingDefinitions` -* The third argument is `actionsAPI`, which is an instance of the `ActionsAPI` class [defined in `aerie-actions`](https://github.com/NASA-AMMOS/aerie-actions/blob/main/src/index.ts#L94). This is your hook for accessing (reading and writing) files and sequences in your workspace, as well as any other helper functions provided by the package. + +- The first argument to `main` is `parameters` - the user-provided parameter values for this run, which will match the structure of your `parameterDefinitions` +- The second argument is `settings` - the user-provided setting values, matching structure of `settingDefinitions` +- The third argument is `actionsAPI`, which is an instance of the `ActionsAPI` class [defined in `aerie-actions`](https://github.com/NASA-AMMOS/aerie-actions/blob/main/src/index.ts#L94). This is your hook for accessing (reading and writing) files and sequences in your workspace, as well as any other helper functions provided by the package. ### Results, Errors and Logs @@ -142,8 +144,9 @@ as long as it is serializable to JSON. Results are saved in the database and dis future, these results may be able to be passed to other actions as parameters, enabling pipelines of actions. If your action encounters a **failure**, you can indicate this in one of two ways: - * You can throw an error eg. `throw new Error('my message');`. When making a call to a function that might fail, *don't* wrap it in a `try/catch`, just let it throw an error - * Or you can `return { status: "FAILED", data: someResults }` with results related to the failure + +- You can throw an error eg. `throw new Error('my message');`. When making a call to a function that might fail, _don't_ wrap it in a `try/catch`, just let it throw an error +- Or you can `return { status: "FAILED", data: someResults }` with results related to the failure Either of these is better than "swallowing" fatal errors by eg. `catch`ing them and logging them, as they will cause the run to properly be reported as a failure in the database and UI. @@ -167,20 +170,65 @@ and examples can be found in the `aerie-action-template`. The basic methods are: // return a list of the names of all sequences in your workspace: const files = await actionsAPI.listSequences(); // get the string contents of a sequence, given the sequence name -const myFileContents = await actionsAPI.readSequence("my_seq"); +const myFileContents = await actionsAPI.readSequence('my_seq'); // overwrite the contents of a sequence with a new string, given the sequence name -const writeResult = await actionsAPI.writeSequence("output_seq", "NEW CONTENTS"); +const writeResult = await actionsAPI.writeSequence('output_seq', 'NEW CONTENTS'); ``` :::caution It is important to `await` these functions (and any other `async` functions you call), or use another -method (eg. `Promise.all`) to ensure that the `Promise`s they return are *resolved* or *rejected* **before** +method (eg. `Promise.all`) to ensure that the `Promise`s they return are _resolved_ or _rejected_ **before** your `main` function returns/resolves. After the `main` Promise is resolved, the process running your Action may be terminated and any unprocessed results will be dropped. ::: +### Accessing secrets in actions + +When an action is run, PlanDev automatically provides several **secrets** to your action via `actionsAPI.config.SECRETS`. +These secrets are transient — they are passed at runtime and never stored in the database. + +**Built-in secrets** (always available): + +- `actionsAPI.config.SECRETS.authorization` — the running user's JWT token (encoded) +- `actionsAPI.config.SECRETS.user` — the running user's JWT payload (decoded JSON string) +- `actionsAPI.config.SECRETS.userRole` — the running user's current Hasura role + +**Forwarded browser cookies** (optional, requires configuration): + +If your deployment uses SSO or other cookie-based authentication, you can configure the action server to +extract specific browser cookies and forward them to actions as secrets. This is useful when an action needs +to authenticate with an external service under the user's identity. + +To enable cookie forwarding, set the following environment variables on the `aerie_action` container: + +| Variable | Description | +| ---------------------------- | ---------------------------------------------------------------------------------------------------------------- | +| `ACTION_COOKIE_NAMES` | Comma-separated list of cookie names to forward (e.g. `ssosession,other_cookie`) | +| `ACTION_CORS_ALLOWED_ORIGIN` | The origin of the PlanDev UI (e.g. `https://your-host.example.com`). **Required** for cookie forwarding to work. | + +Once configured, the specified cookies will be available as secrets: + +```js +export async function main(parameters, settings, actionsAPI) { + const ssoToken = actionsAPI.config.SECRETS.ssosession; + // Use ssoToken to authenticate with an external service +} +``` + +:::caution +**Do not `console.log()` secret values.** Log contents are saved to the database in plaintext. Secret values +are automatically redacted in logs, but return values from your action are **not** redacted — be careful not to +include secret values in your `return` statement's `data` field. +::: + +:::info Deployment note +Cookie forwarding requires that the browser includes cookies in its requests to the action server. This works +automatically when the UI and action server are on the **same origin** (e.g., behind the same reverse proxy). +For **cross-origin** deployments, `ACTION_CORS_ALLOWED_ORIGIN` must be set to the UI's origin. +::: + ### Building your action When you are ready to upload your action to an SeqDev workspace, run this build command: @@ -199,22 +247,23 @@ SeqDev Actions are an **experimental feature** under active development. If you development, [let us know!](http://localhost:3000/plandev-docs/#:~:text=quick%20start%E2%86%92-,Learn%20More,-Ask%20a%20question) Our near-term (Spring 2025) roadmap of upcoming changes to Actions includes: -* More example actions & improved documentation -* Patterns for **testing actions** - User should be able to write tests for their action including mocking & spying on the aerie-actions library (`expect(actions.readSequence).toHaveBeenCalledWith('mySequence')`). -* Action **Cancellation** - Ability to stop a long-running action and kill its worker -* Settle on our **allowed types** of parameters & add some new types, with associated UI for selecting them: + +- More example actions & improved documentation +- Patterns for **testing actions** - User should be able to write tests for their action including mocking & spying on the aerie-actions library (`expect(actions.readSequence).toHaveBeenCalledWith('mySequence')`). +- Action **Cancellation** - Ability to stop a long-running action and kill its worker +- Settle on our **allowed types** of parameters & add some new types, with associated UI for selecting them: - sequence type parameter - 'sequence list' type parameter - 'secret' type? -* Run an action **“on” a particular sequence** - If an action has a sequence-type parameter, you should be able to run it *from* the sequence editor with the active sequence as the parameter value -* Secret storage? - Ability to securely store a setting that is a secret & not display it to end user -* CAM auth token pass-through - If a user deploys PlanDev on **CAM**, and writes an action which makes an HTTP call to another service in the same CAM "walled garden", we should provide a way to pass the token through, so we can be authenticated on the other service. -* **Concurrency** - We don't plan to fully solve the concurrency problem yet, but we should allow *one action per workspace* to run concurrently instead of *one action per PlanDev deployment* -* Rethink **bundling actions** - Currently no way to upload an action with any other configs or scripts to call, you can only upload a single JS file. Should we rethink this to allow a user to give us eg. a node script that calls a python script, packed into a zip file? May also be nice for our action format to have a place to specify version, eg. a manifest file. +- Run an action **“on” a particular sequence** - If an action has a sequence-type parameter, you should be able to run it _from_ the sequence editor with the active sequence as the parameter value +- ~~Secret storage? - Ability to securely store a setting that is a secret & not display it to end user~~ — Partially addressed: browser cookies can be forwarded as transient secrets via `ACTION_COOKIE_NAMES`. See [Accessing secrets in actions](#accessing-secrets-in-actions). +- ~~CAM auth token pass-through~~ — Implemented via cookie forwarding. Configure `ACTION_COOKIE_NAMES` with your SSO cookie name(s) to pass auth tokens through to actions. See [Accessing secrets in actions](#accessing-secrets-in-actions). +- **Concurrency** - We don't plan to fully solve the concurrency problem yet, but we should allow _one action per workspace_ to run concurrently instead of _one action per PlanDev deployment_ +- Rethink **bundling actions** - Currently no way to upload an action with any other configs or scripts to call, you can only upload a single JS file. Should we rethink this to allow a user to give us eg. a node script that calls a python script, packed into a zip file? May also be nice for our action format to have a place to specify version, eg. a manifest file. Our longer-term roadmap includes prospective features such as: -* **Triggers/hooks** - a way to automatically run certain actions when certain things occur, such as a sequence being saved -* **Annotation files** - workspaces should support "annotation files" which are associated with sequences, and contain line-numbered annotations to be displayed in the context of the sequence editor, to support eg. actions running a static checker and showing line-by-line results in the editor. -* **Concurrency** - ability to run multiple actions in the same workspace at the same time, or allow the user to control whether or not this is possible -* **Action pipelines** - connecting action runs together by piping the output results of one action into the input parameters of another. +- **Triggers/hooks** - a way to automatically run certain actions when certain things occur, such as a sequence being saved +- **Annotation files** - workspaces should support "annotation files" which are associated with sequences, and contain line-numbered annotations to be displayed in the context of the sequence editor, to support eg. actions running a static checker and showing line-by-line results in the editor. +- **Concurrency** - ability to run multiple actions in the same workspace at the same time, or allow the user to control whether or not this is possible +- **Action pipelines** - connecting action runs together by piping the output results of one action into the input parameters of another. diff --git a/docs/upgrade-guides/4-0-0-to-4-1-0.md b/docs/upgrade-guides/4-0-0-to-4-1-0.md new file mode 100644 index 0000000..5b89df6 --- /dev/null +++ b/docs/upgrade-guides/4-0-0-to-4-1-0.md @@ -0,0 +1,43 @@ +# 4.0.0 to 4.1.0 + +This document describes the upgrade instructions from `4.0.0` to `4.1.0`. + +## Configuration changes + +### `aerie_action` container config + +Two new **optional** environment variables have been added to the `aerie_action` service to support forwarding browser cookies (e.g., SSO session tokens) to actions as secrets. If you do not need this feature, no changes are required. + +To enable cookie forwarding, add the following to the `aerie_action` section of your docker-compose file: + +```yaml +aerie_action: + environment: + ACTION_COOKIE_NAMES: 'ssosession' # comma-separated list of cookie names to forward + ACTION_CORS_ALLOWED_ORIGIN: 'https://YOUR_HOST_NAME' # origin of your PlanDev UI +``` + +| Variable | Description | Required? | +| ---------------------------- | ------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- | +| `ACTION_COOKIE_NAMES` | Comma-separated list of browser cookie names to extract and forward to actions as secrets | Optional. If unset, no cookies are forwarded. | +| `ACTION_CORS_ALLOWED_ORIGIN` | Allowed CORS origin for the action server. Enables `Access-Control-Allow-Credentials` for cookie forwarding. | Required for cookie forwarding. If unset, cookies will not be sent by the browser in cross-origin deployments. | + +See the [Actions documentation](/sequencing/actions/#accessing-secrets-in-actions) for details on how to access forwarded cookies in action code. + +:::info Same-origin deployments +If your PlanDev UI and action server are served from the **same origin** (e.g., behind the same reverse proxy), cookie forwarding works without `ACTION_CORS_ALLOWED_ORIGIN` since CORS restrictions do not apply to same-origin requests. However, it is still recommended to set it explicitly for security. +::: + +:::caution Cross-origin deployments +If your action server is on a **different origin** than the PlanDev UI, you **must** set `ACTION_CORS_ALLOWED_ORIGIN` to the UI's origin. Without it, the browser will block credentialed requests to the action server. +::: + +## Actions API changes + +Forwarded cookies are available in action code as secrets: + +```js +const ssoToken = actionsAPI.config.SECRETS.ssosession; +``` + +The built-in secrets (`authorization`, `user`, `userRole`) continue to work as before. diff --git a/sidebars.js b/sidebars.js index 58ecee7..6faf184 100644 --- a/sidebars.js +++ b/sidebars.js @@ -517,6 +517,7 @@ const sidebars = { }, ], upgradeGuides: [ + 'upgrade-guides/4-0-0-to-4-1-0', 'upgrade-guides/3-8-1-to-4-0-0', 'upgrade-guides/3-8-0-to-3-8-1', 'upgrade-guides/3-7-1-to-3-8-0', From 3967708a70e6059ac1796d6f1b34bae536cba7ed Mon Sep 17 00:00:00 2001 From: AaronPlave Date: Tue, 24 Feb 2026 06:17:18 -0800 Subject: [PATCH 2/6] Updates to reflect new UI env var --- docs/sequencing/actions.mdx | 27 ++++++++++++++++++--------- docs/upgrade-guides/4-0-0-to-4-1-0.md | 25 +++++++++++++++---------- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/docs/sequencing/actions.mdx b/docs/sequencing/actions.mdx index dfcafbf..2b224ae 100644 --- a/docs/sequencing/actions.mdx +++ b/docs/sequencing/actions.mdx @@ -201,12 +201,13 @@ If your deployment uses SSO or other cookie-based authentication, you can config extract specific browser cookies and forward them to actions as secrets. This is useful when an action needs to authenticate with an external service under the user's identity. -To enable cookie forwarding, set the following environment variables on the `aerie_action` container: +To enable cookie forwarding, set the following environment variables: -| Variable | Description | -| ---------------------------- | ---------------------------------------------------------------------------------------------------------------- | -| `ACTION_COOKIE_NAMES` | Comma-separated list of cookie names to forward (e.g. `ssosession,other_cookie`) | -| `ACTION_CORS_ALLOWED_ORIGIN` | The origin of the PlanDev UI (e.g. `https://your-host.example.com`). **Required** for cookie forwarding to work. | +| Container | Variable | Description | +| -------------- | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------- | +| `aerie_ui` | `PUBLIC_ACTION_INCLUDE_CREDENTIALS` | Set to `true` to include browser credentials (cookies) in requests to the action server | +| `aerie_action` | `ACTION_COOKIE_NAMES` | Comma-separated list of cookie names to forward (e.g. `ssosession,other_cookie`) | +| `aerie_action` | `ACTION_CORS_ALLOWED_ORIGIN` | The origin of the PlanDev UI (e.g. `https://your-host.example.com`). Required for cross-origin deployments. | Once configured, the specified cookies will be available as secrets: @@ -223,10 +224,18 @@ are automatically redacted in logs, but return values from your action are **not include secret values in your `return` statement's `data` field. ::: -:::info Deployment note -Cookie forwarding requires that the browser includes cookies in its requests to the action server. This works -automatically when the UI and action server are on the **same origin** (e.g., behind the same reverse proxy). -For **cross-origin** deployments, `ACTION_CORS_ALLOWED_ORIGIN` must be set to the UI's origin. +:::info Deployment notes +Cookie forwarding requires `PUBLIC_ACTION_INCLUDE_CREDENTIALS=true` on the UI container so the browser includes +cookies in its requests to the action server. For **same-origin** deployments (UI and action server behind the +same reverse proxy), this is sufficient. For **cross-origin** deployments, `ACTION_CORS_ALLOWED_ORIGIN` must +also be set on the action server to the UI's origin. + +**Cookie requirements:** For a browser cookie to be forwarded, it must satisfy the browser's cookie-sending rules: +- The cookie's **domain** must match the action server's domain (or be a parent domain, e.g. `.jpl.nasa.gov`) +- If the cookie has the **`Secure`** flag, the action server must be served over HTTPS +- If the cookie has **`SameSite=Strict`**, the request must be same-site +- **`SameSite=Lax`** (the browser default) will send the cookie for same-origin requests and top-level cross-site navigations +- **`httpOnly`** cookies are supported — this is a key benefit of this feature, since `httpOnly` cookies cannot be read by client-side JavaScript but are still sent by the browser with requests ::: ### Building your action diff --git a/docs/upgrade-guides/4-0-0-to-4-1-0.md b/docs/upgrade-guides/4-0-0-to-4-1-0.md index 5b89df6..ca95f32 100644 --- a/docs/upgrade-guides/4-0-0-to-4-1-0.md +++ b/docs/upgrade-guides/4-0-0-to-4-1-0.md @@ -4,28 +4,33 @@ This document describes the upgrade instructions from `4.0.0` to `4.1.0`. ## Configuration changes -### `aerie_action` container config +### Cookie forwarding for actions -Two new **optional** environment variables have been added to the `aerie_action` service to support forwarding browser cookies (e.g., SSO session tokens) to actions as secrets. If you do not need this feature, no changes are required. +New **optional** environment variables have been added to support forwarding browser cookies (e.g., SSO session tokens) to actions as secrets. If you do not need this feature, no changes are required. -To enable cookie forwarding, add the following to the `aerie_action` section of your docker-compose file: +To enable cookie forwarding, add the following to your docker-compose file: ```yaml +aerie_ui: + environment: + PUBLIC_ACTION_INCLUDE_CREDENTIALS: 'true' # include browser cookies in action server requests + aerie_action: environment: - ACTION_COOKIE_NAMES: 'ssosession' # comma-separated list of cookie names to forward - ACTION_CORS_ALLOWED_ORIGIN: 'https://YOUR_HOST_NAME' # origin of your PlanDev UI + ACTION_COOKIE_NAMES: 'ssosession' # comma-separated list of cookie names to forward + ACTION_CORS_ALLOWED_ORIGIN: 'https://YOUR_HOST_NAME' # origin of your PlanDev UI (required for cross-origin) ``` -| Variable | Description | Required? | -| ---------------------------- | ------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- | -| `ACTION_COOKIE_NAMES` | Comma-separated list of browser cookie names to extract and forward to actions as secrets | Optional. If unset, no cookies are forwarded. | -| `ACTION_CORS_ALLOWED_ORIGIN` | Allowed CORS origin for the action server. Enables `Access-Control-Allow-Credentials` for cookie forwarding. | Required for cookie forwarding. If unset, cookies will not be sent by the browser in cross-origin deployments. | +| Container | Variable | Description | Required? | +| -------------- | ----------------------------------- | ---------------------------------------------------------------------------------------- | --------------------------------------------- | +| `aerie_ui` | `PUBLIC_ACTION_INCLUDE_CREDENTIALS` | Set to `true` to include browser credentials (cookies) in action server requests | Required for cookie forwarding. | +| `aerie_action` | `ACTION_COOKIE_NAMES` | Comma-separated list of browser cookie names to extract and forward to actions as secrets | Required for cookie forwarding. | +| `aerie_action` | `ACTION_CORS_ALLOWED_ORIGIN` | Allowed CORS origin for the action server. Enables `Access-Control-Allow-Credentials`. | Required for cross-origin deployments only. | See the [Actions documentation](/sequencing/actions/#accessing-secrets-in-actions) for details on how to access forwarded cookies in action code. :::info Same-origin deployments -If your PlanDev UI and action server are served from the **same origin** (e.g., behind the same reverse proxy), cookie forwarding works without `ACTION_CORS_ALLOWED_ORIGIN` since CORS restrictions do not apply to same-origin requests. However, it is still recommended to set it explicitly for security. +If your PlanDev UI and action server are served from the **same origin** (e.g., behind the same reverse proxy), `ACTION_CORS_ALLOWED_ORIGIN` is not needed since CORS restrictions do not apply to same-origin requests. You only need `PUBLIC_ACTION_INCLUDE_CREDENTIALS=true` and `ACTION_COOKIE_NAMES`. ::: :::caution Cross-origin deployments From f8593b65a172c91698a93cca913c78b000e40241 Mon Sep 17 00:00:00 2001 From: AaronPlave Date: Tue, 24 Feb 2026 09:14:42 -0800 Subject: [PATCH 3/6] Doc updates --- docs/sequencing/actions.mdx | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/docs/sequencing/actions.mdx b/docs/sequencing/actions.mdx index 2b224ae..b385886 100644 --- a/docs/sequencing/actions.mdx +++ b/docs/sequencing/actions.mdx @@ -203,11 +203,11 @@ to authenticate with an external service under the user's identity. To enable cookie forwarding, set the following environment variables: -| Container | Variable | Description | -| -------------- | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -| `aerie_ui` | `PUBLIC_ACTION_INCLUDE_CREDENTIALS` | Set to `true` to include browser credentials (cookies) in requests to the action server | -| `aerie_action` | `ACTION_COOKIE_NAMES` | Comma-separated list of cookie names to forward (e.g. `ssosession,other_cookie`) | -| `aerie_action` | `ACTION_CORS_ALLOWED_ORIGIN` | The origin of the PlanDev UI (e.g. `https://your-host.example.com`). Required for cross-origin deployments. | +| Container | Variable | Description | +| -------------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------- | +| `aerie_ui` | `PUBLIC_ACTION_INCLUDE_CREDENTIALS` | Set to `true` to include browser credentials (cookies) in requests to the action server | +| `aerie_action` | `ACTION_COOKIE_NAMES` | Comma-separated list of cookie names to forward (e.g. `ssosession,other_cookie`) | +| `aerie_action` | `ACTION_CORS_ALLOWED_ORIGIN` | The origin of the PlanDev UI (e.g. `https://your-host.example.com`). Required for cross-origin deployments. | Once configured, the specified cookies will be available as secrets: @@ -231,12 +231,13 @@ same reverse proxy), this is sufficient. For **cross-origin** deployments, `ACTI also be set on the action server to the UI's origin. **Cookie requirements:** For a browser cookie to be forwarded, it must satisfy the browser's cookie-sending rules: + - The cookie's **domain** must match the action server's domain (or be a parent domain, e.g. `.jpl.nasa.gov`) - If the cookie has the **`Secure`** flag, the action server must be served over HTTPS - If the cookie has **`SameSite=Strict`**, the request must be same-site - **`SameSite=Lax`** (the browser default) will send the cookie for same-origin requests and top-level cross-site navigations - **`httpOnly`** cookies are supported — this is a key benefit of this feature, since `httpOnly` cookies cannot be read by client-side JavaScript but are still sent by the browser with requests -::: + ::: ### Building your action @@ -255,18 +256,10 @@ then reupload it to SeqDev. SeqDev Actions are an **experimental feature** under active development. If you have feedback or ideas for their future development, [let us know!](http://localhost:3000/plandev-docs/#:~:text=quick%20start%E2%86%92-,Learn%20More,-Ask%20a%20question) -Our near-term (Spring 2025) roadmap of upcoming changes to Actions includes: +Our near-term roadmap of upcoming changes to Actions includes: - More example actions & improved documentation - Patterns for **testing actions** - User should be able to write tests for their action including mocking & spying on the aerie-actions library (`expect(actions.readSequence).toHaveBeenCalledWith('mySequence')`). -- Action **Cancellation** - Ability to stop a long-running action and kill its worker -- Settle on our **allowed types** of parameters & add some new types, with associated UI for selecting them: - - sequence type parameter - - 'sequence list' type parameter - - 'secret' type? -- Run an action **“on” a particular sequence** - If an action has a sequence-type parameter, you should be able to run it _from_ the sequence editor with the active sequence as the parameter value -- ~~Secret storage? - Ability to securely store a setting that is a secret & not display it to end user~~ — Partially addressed: browser cookies can be forwarded as transient secrets via `ACTION_COOKIE_NAMES`. See [Accessing secrets in actions](#accessing-secrets-in-actions). -- ~~CAM auth token pass-through~~ — Implemented via cookie forwarding. Configure `ACTION_COOKIE_NAMES` with your SSO cookie name(s) to pass auth tokens through to actions. See [Accessing secrets in actions](#accessing-secrets-in-actions). - **Concurrency** - We don't plan to fully solve the concurrency problem yet, but we should allow _one action per workspace_ to run concurrently instead of _one action per PlanDev deployment_ - Rethink **bundling actions** - Currently no way to upload an action with any other configs or scripts to call, you can only upload a single JS file. Should we rethink this to allow a user to give us eg. a node script that calls a python script, packed into a zip file? May also be nice for our action format to have a place to specify version, eg. a manifest file. From 287cc544811626a42069fa22b6a4dfc6449ec292 Mon Sep 17 00:00:00 2001 From: AaronPlave Date: Wed, 25 Feb 2026 07:29:06 -0800 Subject: [PATCH 4/6] Remove upgrade guide --- docs/upgrade-guides/4-0-0-to-4-1-0.md | 48 --------------------------- sidebars.js | 1 - 2 files changed, 49 deletions(-) delete mode 100644 docs/upgrade-guides/4-0-0-to-4-1-0.md diff --git a/docs/upgrade-guides/4-0-0-to-4-1-0.md b/docs/upgrade-guides/4-0-0-to-4-1-0.md deleted file mode 100644 index ca95f32..0000000 --- a/docs/upgrade-guides/4-0-0-to-4-1-0.md +++ /dev/null @@ -1,48 +0,0 @@ -# 4.0.0 to 4.1.0 - -This document describes the upgrade instructions from `4.0.0` to `4.1.0`. - -## Configuration changes - -### Cookie forwarding for actions - -New **optional** environment variables have been added to support forwarding browser cookies (e.g., SSO session tokens) to actions as secrets. If you do not need this feature, no changes are required. - -To enable cookie forwarding, add the following to your docker-compose file: - -```yaml -aerie_ui: - environment: - PUBLIC_ACTION_INCLUDE_CREDENTIALS: 'true' # include browser cookies in action server requests - -aerie_action: - environment: - ACTION_COOKIE_NAMES: 'ssosession' # comma-separated list of cookie names to forward - ACTION_CORS_ALLOWED_ORIGIN: 'https://YOUR_HOST_NAME' # origin of your PlanDev UI (required for cross-origin) -``` - -| Container | Variable | Description | Required? | -| -------------- | ----------------------------------- | ---------------------------------------------------------------------------------------- | --------------------------------------------- | -| `aerie_ui` | `PUBLIC_ACTION_INCLUDE_CREDENTIALS` | Set to `true` to include browser credentials (cookies) in action server requests | Required for cookie forwarding. | -| `aerie_action` | `ACTION_COOKIE_NAMES` | Comma-separated list of browser cookie names to extract and forward to actions as secrets | Required for cookie forwarding. | -| `aerie_action` | `ACTION_CORS_ALLOWED_ORIGIN` | Allowed CORS origin for the action server. Enables `Access-Control-Allow-Credentials`. | Required for cross-origin deployments only. | - -See the [Actions documentation](/sequencing/actions/#accessing-secrets-in-actions) for details on how to access forwarded cookies in action code. - -:::info Same-origin deployments -If your PlanDev UI and action server are served from the **same origin** (e.g., behind the same reverse proxy), `ACTION_CORS_ALLOWED_ORIGIN` is not needed since CORS restrictions do not apply to same-origin requests. You only need `PUBLIC_ACTION_INCLUDE_CREDENTIALS=true` and `ACTION_COOKIE_NAMES`. -::: - -:::caution Cross-origin deployments -If your action server is on a **different origin** than the PlanDev UI, you **must** set `ACTION_CORS_ALLOWED_ORIGIN` to the UI's origin. Without it, the browser will block credentialed requests to the action server. -::: - -## Actions API changes - -Forwarded cookies are available in action code as secrets: - -```js -const ssoToken = actionsAPI.config.SECRETS.ssosession; -``` - -The built-in secrets (`authorization`, `user`, `userRole`) continue to work as before. diff --git a/sidebars.js b/sidebars.js index 6faf184..58ecee7 100644 --- a/sidebars.js +++ b/sidebars.js @@ -517,7 +517,6 @@ const sidebars = { }, ], upgradeGuides: [ - 'upgrade-guides/4-0-0-to-4-1-0', 'upgrade-guides/3-8-1-to-4-0-0', 'upgrade-guides/3-8-0-to-3-8-1', 'upgrade-guides/3-7-1-to-3-8-0', From 0ec903717e05c8032db51a15672cd3868c3ffaa8 Mon Sep 17 00:00:00 2001 From: AaronPlave Date: Wed, 25 Feb 2026 13:17:00 -0800 Subject: [PATCH 5/6] Update --- docs/sequencing/actions.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sequencing/actions.mdx b/docs/sequencing/actions.mdx index b385886..635109b 100644 --- a/docs/sequencing/actions.mdx +++ b/docs/sequencing/actions.mdx @@ -209,11 +209,11 @@ To enable cookie forwarding, set the following environment variables: | `aerie_action` | `ACTION_COOKIE_NAMES` | Comma-separated list of cookie names to forward (e.g. `ssosession,other_cookie`) | | `aerie_action` | `ACTION_CORS_ALLOWED_ORIGIN` | The origin of the PlanDev UI (e.g. `https://your-host.example.com`). Required for cross-origin deployments. | -Once configured, the specified cookies will be available as secrets: +Once configured, the specified cookies will be available under `actionsAPI.config.SECRETS.cookies`: ```js export async function main(parameters, settings, actionsAPI) { - const ssoToken = actionsAPI.config.SECRETS.ssosession; + const ssoToken = actionsAPI.config.SECRETS.cookies.ssosession; // Use ssoToken to authenticate with an external service } ``` From 32c74ccf64b6423ee86afb15e4eb8ed4d7aed2bb Mon Sep 17 00:00:00 2001 From: Dan Delany Date: Wed, 25 Feb 2026 16:55:55 -0800 Subject: [PATCH 6/6] improve docs for action secrets --- docs/sequencing/actions.mdx | 40 +++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/docs/sequencing/actions.mdx b/docs/sequencing/actions.mdx index 635109b..d91191e 100644 --- a/docs/sequencing/actions.mdx +++ b/docs/sequencing/actions.mdx @@ -195,6 +195,34 @@ These secrets are transient — they are passed at runtime and never stored in t - `actionsAPI.config.SECRETS.user` — the running user's JWT payload (decoded JSON string) - `actionsAPI.config.SECRETS.userRole` — the running user's current Hasura role +**Secret parameters** + +Your action may define parameters with `type: "secret"`, which causes them to be handled as transient secret-type +parameters. Unlike other parameters, these will not be stored in the database and will be sent directly to the action +only once, at the time you run your action. These are useful for passing some short-lived auth tokens to third-party +services which may require them. For example: + +```js +export const parameterDefinitions = { + mySecretAuthToken: { type: 'secret' } +}; +``` + +Use secret parameters judiciously - since their values are not stored, they cannot be audited after the action run to +reproduce the same results later. + +**Environment variables** + +For security reasons, actions cannot access all environment variables that are set on the `aerie_action` container. +However, for storing and passing long-lived secrets to your actions, you can make certain environment variables +accessible by adding the prefix `PUBLIC_ACTION_` to their name, for example: + +```yaml +PUBLIC_ACTION_MY_SECRET_API_KEY: "someTokenThatWillLastForAWhile" +``` + +These will be accessible in the action under the global `process.env`. + **Forwarded browser cookies** (optional, requires configuration): If your deployment uses SSO or other cookie-based authentication, you can configure the action server to @@ -207,7 +235,7 @@ To enable cookie forwarding, set the following environment variables: | -------------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------- | | `aerie_ui` | `PUBLIC_ACTION_INCLUDE_CREDENTIALS` | Set to `true` to include browser credentials (cookies) in requests to the action server | | `aerie_action` | `ACTION_COOKIE_NAMES` | Comma-separated list of cookie names to forward (e.g. `ssosession,other_cookie`) | -| `aerie_action` | `ACTION_CORS_ALLOWED_ORIGIN` | The origin of the PlanDev UI (e.g. `https://your-host.example.com`). Required for cross-origin deployments. | +| `aerie_action` | `ACTION_CORS_ALLOWED_ORIGIN` | The origin of the PlanDev UI (e.g. `https://your-host.example.com`). | Once configured, the specified cookies will be available under `actionsAPI.config.SECRETS.cookies`: @@ -225,19 +253,15 @@ include secret values in your `return` statement's `data` field. ::: :::info Deployment notes -Cookie forwarding requires `PUBLIC_ACTION_INCLUDE_CREDENTIALS=true` on the UI container so the browser includes -cookies in its requests to the action server. For **same-origin** deployments (UI and action server behind the -same reverse proxy), this is sufficient. For **cross-origin** deployments, `ACTION_CORS_ALLOWED_ORIGIN` must -also be set on the action server to the UI's origin. - -**Cookie requirements:** For a browser cookie to be forwarded, it must satisfy the browser's cookie-sending rules: +**Cookie requirements:** For a browser cookie to be forwarded, the environment variables noted above must be set, +**and** the whitelisted cookies must **also** satisfy the browser's cookie-sending rules: - The cookie's **domain** must match the action server's domain (or be a parent domain, e.g. `.jpl.nasa.gov`) - If the cookie has the **`Secure`** flag, the action server must be served over HTTPS - If the cookie has **`SameSite=Strict`**, the request must be same-site - **`SameSite=Lax`** (the browser default) will send the cookie for same-origin requests and top-level cross-site navigations - **`httpOnly`** cookies are supported — this is a key benefit of this feature, since `httpOnly` cookies cannot be read by client-side JavaScript but are still sent by the browser with requests - ::: +::: ### Building your action