Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,40 @@ jobs:
run: |
yarn
yarn test

integration_test:
runs-on: ubuntu-24.04
needs: build_and_test
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 24.x
- uses: browser-actions/setup-chrome@latest
id: setup-chrome
with:
chrome-version: stable
install-chromedriver: true
- name: install dependencies
run: yarn
- name: write project credentials
run: |
echo '${{ secrets.INTEGRATION_PROJECT_JSON }}' > integration/projects/project.json
echo '${{ secrets.INTEGRATION_PRIVATE_KEY }}' > integration/projects/private.key
- name: start integration servers
run: |
yarn start &
for port in 4500 4501; do
for i in $(seq 1 30); do
if curl -sk https://localhost:$port > /dev/null 2>&1; then
echo "Server on port $port is ready"
break
fi
sleep 1
done
done
- name: run nightwatch tests
env:
CHROME_PATH: ${{ steps.setup-chrome.outputs.chrome-path }}
CHROMEDRIVER_PATH: ${{ steps.setup-chrome.outputs.chromedriver-path }}
run: yarn nightwatch
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ bin/
dist/
docs/
coverage/
integration/private.key
integration/projects/*
!integration/projects/*.iron
integration/certs/*
.direnv
logs/
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ The IronWeb SDK NPM releases follow standard [Semantic Versioning](https://semve

**Note:** The patch versions of the IronWeb SDK will not be sequential and might jump by multiple numbers between sequential releases.

## v4.3.1

- fix a streaming bug, encrypt could get blocked with no reader yet on writing the header+IV.
- fix a bug in unmanaged encryption if ironweb was used without a bundler that could provide a `Buffer` polyfill.

## v4.3.0
- add streaming encrypt and decrypt functionality for managed and unmanaged documents.

Expand Down
8 changes: 7 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,20 @@
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
pkgs = import nixpkgs {
inherit system;
config.allowUnfreePredicate = pkg:
builtins.elem (nixpkgs.lib.getName pkg) [ "google-chrome" ];
};
in
{
devShell = pkgs.mkShell {
buildInputs = [
pkgs.prettier
pkgs.nodejs_24
(pkgs.yarn.override { nodejs = pkgs.nodejs_24; })
pkgs.google-chrome
pkgs.chromedriver
];
};
});
Expand Down
97 changes: 97 additions & 0 deletions integration/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Integration Tests

## Architecture

The integration test setup has three components:

1. **Client app** (`clientHost.webpack.js`) — serves the demo app at `https://localhost:4500`. This is the UI that nightwatch interacts with.
2. **Frame/Worker host** (`iclHost.webpack.js`) — serves the iframe + web worker code at `https://localhost:4501`. This is where the SDK's frame and crypto worker run, built from your local source.
3. **API backend** — by default, API requests are proxied to stage ironcore-id (`https://api-staging.ironcorelabs.com`). Set `API_PROXY_TARGET=http://localhost:9090` to use a local ironcore-id instead.

All three SDK layers (shim, frame, worker) run locally from source, so your uncommitted changes are under test.

## Prerequisites

### Nix dev shell (recommended)

The project flake provides everything you need: Node.js, yarn, Chrome, and ChromeDriver (version-matched from the same nixpkgs):

```bash
nix develop
```

### Project credentials

The project credentials are encrypted with ironhide. Decrypt them before first use:

```bash
ironhide file decrypt integration/projects/*
```

This produces `integration/projects/project.json` and `integration/projects/private.key`, which contain the project ID, segment ID, identity assertion key ID, and signing key for the stage environment.

## Running the Integration App

```bash
yarn start
```

This generates self-signed localhost TLS certs (if not already present) and starts both webpack dev servers in parallel (client on port 4500, frame on port 4501).

Navigate to **`https://localhost:4500`** in your browser (the `https://` is required). If your browser shows a certificate warning for the self-signed cert, click through to proceed.

### Testing against a hosted frame environment

To test against a specific deployed frame version (e.g. to reproduce a reported bug or confirm a regression against a release), set `HOSTED_ENV` and `HOSTED_VERSION`. This loads the frame and worker from the remote environment instead of local source:

```bash
HOSTED_VERSION=4.3.1 HOSTED_ENV=stage yarn start
```

In this mode the client app still runs locally, but the iframe loads from the remote environment (e.g. `https://api-staging.ironcorelabs.com`). Local changes to frame or worker code will **not** be reflected — only shim changes are tested.

Available environments: `stage`, `dev`, `prod`.

### Environment variables

| Variable | Default | Description |
|--------------------|--------------------------------------------|--------------------------------------------|
| `CLIENT_HOST` | `localhost` | Hostname for the client app server |
| `CLIENT_PORT` | `4500` | Port for the client app server |
| `FRAME_HOST` | `localhost` | Hostname for the frame/worker server |
| `FRAME_PORT` | `4501` | Port for the frame/worker server |
| `CLIENT_CERT_DIR` | `certs/localhost` | TLS cert directory for the client server |
| `FRAME_CERT_DIR` | `certs/localhost` | TLS cert directory for the frame server |
| `API_PROXY_TARGET` | `https://api-staging.ironcorelabs.com` | Backend API to proxy `/api/1/` requests to |
| `HOSTED_ENV` | _(unset)_ | Load frame from a remote env instead of local (`stage`, `dev`, `prod`) |
| `HOSTED_VERSION` | _(unset)_ | SDK version string (required with `HOSTED_ENV`) |

## Running Nightwatch Tests

### 1. Start the integration app

```bash
yarn start
```

### 2. Run tests

Run all tests:

```bash
yarn nightwatch
```

Run tests by tag:

```bash
yarn nightwatch --tag unmanagedEncrypt
```

## Test Tags

| Tag | Test file | Description |
|-----------------------------|--------------------------------------------------|--------------------------------------------------|
| `unmanagedEncrypt` | `document-unmanaged-encrypt.test.js` | Unmanaged encrypt/decrypt round-trip |
| `streamingEncrypt` | `document-streaming-encrypt.test.js` | Streaming encrypt/decrypt round-trip |
| `unmanagedStreamingEncrypt` | `document-unmanaged-streaming-encrypt.test.js` | Unmanaged streaming encrypt/decrypt round-trip |
19 changes: 9 additions & 10 deletions integration/clientHost.webpack.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ const projectIDs = require("./projects/project.json");
const keyFile = path.join(__dirname, "./projects/private.key");
const privateKey = fs.readFileSync(keyFile, "utf8");

const SB_HOST = "dev1.scrambledbits.org";
const SB_PORT = 4500;
const SB_HOST = process.env.CLIENT_HOST || "localhost";
const SB_PORT = parseInt(process.env.CLIENT_PORT, 10) || 4500;
const FRAME_HOST = process.env.FRAME_HOST || "localhost";
const FRAME_PORT = parseInt(process.env.FRAME_PORT, 10) || 4501;
const CERT_DIR = path.join(__dirname, process.env.CLIENT_CERT_DIR || "certs/localhost");

if ((process.env.HOSTED_VERSION && !process.env.HOSTED_ENV) || (!process.env.HOSTED_VERSION && process.env.HOSTED_ENV)) {
throw new Error("In order to run against a non-local environment you need to set both the `HOSTED_VERSION` and `HOSTED_ENV` environment variables.");
Expand All @@ -26,12 +29,10 @@ function getFrameDomain() {
case "dev":
return "https://api-dev1.ironcorelabs.com";
default:
return "https://dev1.ironcorelabs.com:4501";
return `https://${FRAME_HOST}:${FRAME_PORT}`;
}
}

const runtimeEnvironment = process.env.HOSTED_VERSION ? "production" : "";

/**
* Serve the app index.html page. This figures out who the current user is, and if one doesn't exist, generates a new random user
*/
Expand Down Expand Up @@ -72,7 +73,7 @@ function serveIndex(req, res) {
*/
function serveJWT(req, res) {
res.json(
jwt.sign({pid: projectIDs.projectId, sid: projectIDs.segmentId, kid: projectIDs.serviceKeyId || undefined}, privateKey, {
jwt.sign({pid: projectIDs.projectId, sid: projectIDs.segmentId, kid: projectIDs.identityAssertionKeyId}, privateKey, {
algorithm: "ES256",
expiresIn: "2m",
subject: req.params.userID,
Expand All @@ -92,9 +93,8 @@ module.exports = {
server: {
type: "https",
options: {
key: fs.readFileSync(path.join(__dirname, "certs/sb/privkey.pem")),
cert: fs.readFileSync(path.join(__dirname, "certs/sb/cert.pem")),
ca: fs.readFileSync(path.join(__dirname, "certs/sb/chain.pem")),
key: fs.readFileSync(path.join(CERT_DIR, "privkey.pem")),
cert: fs.readFileSync(path.join(CERT_DIR, "cert.pem")),
},
},
setupMiddlewares: (middlewares, devServer) => {
Expand Down Expand Up @@ -131,7 +131,6 @@ module.exports = {
},
plugins: [
new webpack.DefinePlugin({
//"process.env.NODE_ENV": JSON.stringify(runtimeEnvironment), not sure why this conflicting problem comes up
SDK_NPM_VERSION_PLACEHOLDER: JSON.stringify(process.env.HOSTED_VERSION || "SDK_NPM_VERSION_PLACEHOLDER"),
_ICL_FRAME_DOMAIN_REPLACEMENT_: JSON.stringify(getFrameDomain()),
}),
Expand Down
2 changes: 1 addition & 1 deletion integration/components/UserInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export default class UserInfo extends React.Component<Record<string, never>, Use
passcodeError: false,
changingPasscode: false,
listingDevices: false,
loading: true,
loading: false,
deviceList: [],
};
}
Expand Down
Loading