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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions .github/workflows/publish-to-npm.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
name: Publish to NPM

# user creates a GH release with a new `vX.X.X` tag to trigger this workflow
on:
push:
tags:
Expand All @@ -14,21 +15,26 @@ permissions:
jobs:
publish-to-npm:
runs-on: ubuntu-latest
# use github environment so we can have an approval policy for workflow runs
environment: publish
steps:
- name: Check out repository
uses: actions/checkout@v6
# general policy: pin `uses` dependencies to commit hashes to avoid tag-poisoning attacks
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
# throw away GH token after this step so future steps can't use it
persist-credentials: false

- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: .nvmrc
registry-url: https://registry.npmjs.org
# don't use NPM cache when installing, to avoid possibility of cache-poisoning attacks during publish
package-manager-cache: false

- name: Verify release version
# fail & warn if release git tag doesn't match version in `package.json`
run: >-
node -e "
const { version } = require('./package.json');
Expand All @@ -39,22 +45,24 @@ jobs:
"

- name: Install dependencies
# use `npm ci` for reproducible installs, fails if package & lock files are out of sync
# install without running lifecycle scripts, then run only scripts approved in package.json's `allowScripts`
run: |
npm ci --ignore-scripts
# isolated-vm requires its lifecycle scripts to build the native addon.
npm rebuild isolated-vm

- name: Test
run: npm test
npm rebuild --strict-allow-scripts

- name: Build
run: npm run build

- name: Test
run: npm test

- name: Verify package contents
# list all files in the published package, for logs/traceability
run: npm pack --dry-run

- name: Publish
env:
# git tags like `v1.0.0-rc.0` will be tagged as `next` version in NPM instead of `latest`
# pre-release git tags like `v1.0.0-rc.0` will be tagged as `next` version in NPM instead of `latest`
NPM_DIST_TAG: ${{ contains(github.ref_name, '-') && 'next' || 'latest' }}
run: npm publish --tag "$NPM_DIST_TAG"
22 changes: 13 additions & 9 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,31 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v6
# general policy: pin `uses` dependencies to commit hashes to avoid tag-poisoning attacks
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
# throw away GH token after this step so future steps can't use it
persist-credentials: false

- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: .nvmrc
registry-url: https://registry.npmjs.org
cache: npm
cache-dependency-path: package-lock.json

- name: Install Dependencies
- name: Install dependencies
# use `npm ci` for reproducible installs, fails if package & lock files are out of sync
# install without running lifecycle scripts, then run only scripts approved in package.json's `allowScripts`
run: |
npm ci --ignore-scripts
# isolated-vm requires its lifecycle scripts to build the native addon.
npm rebuild isolated-vm
npm rebuild --strict-allow-scripts

- name: Build
run: npm run build

- name: Test
id: test
env:
NO_COLOR: 1
run: npm run test:ci

- name: Add Test Summary
Expand All @@ -50,7 +54,7 @@ jobs:

- name: Upload Test Results
if: always()
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: test-results-${{ github.run_id }}
path: test-output.txt
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

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

15 changes: 12 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"name": "@nasa-jpl/aerie-ts-user-code-runner",
"version": "1.0.0",
"name": "@nasa-jpl/plandev-ts-user-code-runner",
"version": "1.1.0",
"description": "A simple way to safely run user code written in Typescript.",
"repository": {
"type": "git",
"url": "https://github.com/NASA-AMMOS/aerie-ts-user-code-runner"
"url": "https://github.com/NASA-AMMOS/plandev-ts-user-code-runner"
},
"main": "build/UserCodeRunner.js",
"type": "module",
Expand Down Expand Up @@ -44,5 +44,14 @@
"fsevents@2.3.3": true,
"isolated-vm@6.0.2": true,
"esbuild@0.28.2": true
},
"publishConfig": {
"access": "public"
},
"devEngines": {
"packageManager": {
"name": "npm",
"onFail": "warn"
}
}
}
54 changes: 27 additions & 27 deletions test/UserCodeRunner.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ describe('behavior', () => {
return Object.keys(globalThis).join(',');
}
`.trimTemplate();

const runner = new UserCodeRunner();

const result = await runner.executeUserCode(
userCode,
[],
'string',
[],
);

expect(result.isOk()).toBe(true);
expect(result.unwrap()).toBe('__args,__result');
});
Expand Down Expand Up @@ -132,7 +132,7 @@ describe('behavior', () => {
subroutine();
return thing + ' world';
}

function subroutine() {
throw new Error('This is a test error');
}
Expand Down Expand Up @@ -186,7 +186,7 @@ describe('behavior', () => {
export function throwingLibraryFunction(): void {
throw new Error("Error in library code")
}

Object.assign(globalThis, { throwingLibraryFunction });
`.trimTemplate(), ts.ScriptTarget.ESNext, true),
],
Expand All @@ -212,7 +212,7 @@ describe('behavior', () => {
subroutine();
return thing + ' world';
}

function subroutine() {
throw new Error('This is a test error');
}
Expand Down Expand Up @@ -247,7 +247,7 @@ describe('behavior', () => {
subroutine();
return thing + ' world';
}

function subroutine() {
throw new Error('This is a test error');
}
Expand Down Expand Up @@ -282,7 +282,7 @@ describe('behavior', () => {
subroutine();
return thing + ' world';
}

function subroutine() {
throw new Error('This is a test error');
}
Expand Down Expand Up @@ -317,7 +317,7 @@ describe('behavior', () => {
subroutine();
return thing + ' world';
}

function subroutine() {
throw new Error('This is a test error');
}
Expand Down Expand Up @@ -354,7 +354,7 @@ describe('behavior', () => {
subroutine();
return thing + ' world';
}

function subroutine() {
throw new Error('This is a test error');
}
Expand Down Expand Up @@ -588,7 +588,7 @@ describe('behavior', () => {
const myExpansion = (props: ExpansionProps): ExpansionReturn => {
const { activity } = props;
const { biteSize } = activity.attributes.arguments;

return [
AVS_DMP_ADC_SNAPSHOT(biteSize)
];
Expand Down Expand Up @@ -638,7 +638,7 @@ describe('behavior', () => {
const myExpansion = function(props: ExpansionProps): ExpansionReturn {
const { activity } = props;
const { biteSize } = activity.attributes.arguments;

return [
AVS_DMP_ADC_SNAPSHOT(biteSize)
];
Expand Down Expand Up @@ -686,7 +686,7 @@ describe('behavior', () => {
export default function MyDSLFunction(thing: string): string {
return thing + ' world';
}

throw new Error('This is a test error');
`.trimTemplate();

Expand Down Expand Up @@ -782,7 +782,7 @@ This is a test error
subroutine();
return thing + ' world';
}

function subroutine() {
throw new Error('This is a test error');
}
Expand Down Expand Up @@ -818,7 +818,7 @@ This is a test error
await subroutine();
return thing + ' world';
}

async function subroutine() {
throw new Error('This is a test error');
}
Expand Down Expand Up @@ -872,7 +872,7 @@ This is a test error
export function throwingLibraryFunction(): void {
throw new Error("Error in library code")
}

Object.assign(globalThis, { throwingLibraryFunction });
`.trimTemplate(), ts.ScriptTarget.ESNext, true),
],
Expand All @@ -898,7 +898,7 @@ This is a test error
subroutine();
return thing + ' world';
}

function subroutine() {
throw new Error('This is a test error');
}
Expand Down Expand Up @@ -933,7 +933,7 @@ This is a test error
subroutine();
return thing + ' world';
}

function subroutine() {
throw new Error('This is a test error');
}
Expand Down Expand Up @@ -1053,7 +1053,7 @@ This is a test error
});

describe('regression tests', () => {
test('Aerie command expansion throw Regression Test', async () => {
test('PlanDev command expansion throw Regression Test', async () => {
const userCode = `
export default function SingleCommandExpansion(props: { activity: ActivityType }): Command {
const duration = Temporal.Duration.from('PT1H');
Expand Down Expand Up @@ -1086,7 +1086,7 @@ describe('regression tests', () => {
return new Duration();
}
}

Object.defineProperty(globalThis, 'Temporal', {
value: { Duration },
writable: false,
Expand All @@ -1105,7 +1105,7 @@ describe('regression tests', () => {
});
})

test('Aerie undefined node test', async () => {
test('PlanDev undefined node test', async () => {
const userCode = `
export default function BakeBananaBreadExpansionLogic(
props: {
Expand Down Expand Up @@ -1186,7 +1186,7 @@ describe('regression tests', () => {
});
});

test('Aerie Scheduler test', async () => {
test('PlanDev Scheduler test', async () => {
const userCode = `
export default function myGoal() {
return myHelper(ActivityTemplates.PeelBanana({
Expand Down Expand Up @@ -1245,7 +1245,7 @@ describe('regression tests', () => {
});
});

test('Aerie Scheduler TS2345 regression test', async () => {
test('PlanDev Scheduler TS2345 regression test', async () => {
const userCode = `
export default function myGoal() {
return myHelper(ActivityTemplates.PeelBanana({ peelDirection: 'fromStem' }))
Expand Down Expand Up @@ -1294,7 +1294,7 @@ describe('regression tests', () => {
});
});

test("Aerie Scheduler wrong return type no annotation regression test", async () => {
test("PlanDev Scheduler wrong return type no annotation regression test", async () => {
const userCode = `
export default function myGoal<T>() {
return 5
Expand Down Expand Up @@ -1454,7 +1454,7 @@ describe('regression tests', () => {
});
});

test('Aerie command expansion invalid count regression test', async () => {
test('PlanDev command expansion invalid count regression test', async () => {
const userCode = `
export default function SingleCommandExpansion(): ExpansionReturn {
return DDM_CLOSE_OPEN_SELECT_DP;
Expand Down Expand Up @@ -1516,7 +1516,7 @@ describe('regression tests', () => {
});
});

test('Aerie scheduler unmapped harness error on missing property return type', async () => {
test('PlanDev scheduler unmapped harness error on missing property return type', async () => {
const userCode = `
interface FakeGoal {
and(...others: FakeGoal[]): FakeGoal;
Expand Down Expand Up @@ -1568,7 +1568,7 @@ describe('regression tests', () => {
});
});

test('Aerie incorrect stack frame assumption regression test', async () => {
test('PlanDev incorrect stack frame assumption regression test', async () => {
const userCode = `
export default () => {
return Real.Resource("state of charge").lessThan(0.3).split(0)
Expand Down