Skip to content

Commit

Permalink
Merge branch 'master' into markm-byte-array-2
Browse files Browse the repository at this point in the history
  • Loading branch information
erights committed Jul 3, 2024
2 parents f51b94e + 201ceeb commit 5eb079d
Show file tree
Hide file tree
Showing 30 changed files with 459 additions and 273 deletions.
20 changes: 13 additions & 7 deletions .github/workflows/browser-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,19 @@ jobs:
browser-tests:
timeout-minutes: 30
runs-on: ubuntu-latest
container:
image: selenium/standalone-chrome:nightly
options: --user root # reintroducing a GH Actions default expectation
## https://docs.github.com/en/actions/creating-actions/dockerfile-support-for-github-actions#user
## the Selenium image is configured to not run as root, so we have to undo some of it
env:
HOME: /root # Firefox complains otherwise
# This Chrome nightly image can no longer install browsers in Github CI for
# lack of some system dependencies:
# Package 'libasound2' has no installation candidate
# Unable to locate package libicu70
# Unable to locate package libffi7
# Unable to locate package libx264-163
# container:
# image: selenium/standalone-chrome:nightly
# options: --user root # reintroducing a GH Actions default expectation
# ## https://docs.github.com/en/actions/creating-actions/dockerfile-support-for-github-actions#user
# ## the Selenium image is configured to not run as root, so we have to undo some of it
# env:
# HOME: /root # Firefox complains otherwise
steps:
- name: Put unstable chrome where playwright would look for it
run: mv /opt/google/chrome /opt/google/chrome-unstable
Expand Down
90 changes: 55 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,26 @@
[![contributing][contributing-svg]][contributing-url]
[![license][license-image]][license-url]

Endo is a JavaScript platform under development for secure communication among
objects within one process and distributed between mutually suspicious
machines.

The foundation of Endo is Hardened JavaScript as implemented by [`ses`][SES], a
tamper-proof JavaScript environment that allows safe execution of arbitrary
programs in Compartments.
Most JavaScript libraries built for Node.js, either in CommonJS or ECMAScript
module format, are suitable for running in Endo without modification, since
such programs rarely tamper with global scope or shared intrinsic objects.
The exception is shims, which require special treatment and express consent to
work with Endo.
Endo is a framework for powerful JavaScript plugin systems and supply chain
attack resistance.
Endo includes tools for _confinement_, _communication_, and _concurrency_.
These include a shim for [Hardened JavaScript][SES], an [ECMA TC-39
standards track proposal][SES Proposal] to make JavaScript a safer and more
suitable platform for plugin systems.

Agoric and MetaMask rely on Hardened JavaScript and the [SES shim][SES] as part
of systems that sandbox third-party plugins or smart contracts and mitigate
supply chain attacks for production web applications, web extensions, and build
systems.

[![Agoric Logo](https://github.com/endojs/endo/raw/master/packages/ses/docs/agoric-x100.png)](https://agoric.com/)
[![MetaMask Logo](https://github.com/endojs/endo/raw/master/packages/ses/docs/metamask-x100.png)](https://metamask.io/)

Endo protects program integrity both in-process and in distributed systems.
Hardened JavaScript protects local integrity, defending an application against
[supply chain attacks][]: hacks that enter through upgrades to third-party
dependencies.
Endo does this by encouraging the [Principle of Least Authority][POLA].

**POLA explained in 3 minutes:**
_Opening Statement on SOSP 50th Anniversary Panel_, Mark Miller:

[![Video presentation explaining POLA in 3 minutes](https://img.youtube.com/vi/br9DwtjqmVI/0.jpg)](https://www.youtube.com/watch?v=br9DwtjqmVI)

**POLA explained in 15 minutes:**
_Navigating the Attack Surface to achieve a multiplicative reduction in risk_,
Mark Miller:

[![Video presentation explaining POLA in 15 minutes](https://img.youtube.com/vi/wW9-KuezPp8/0.jpg)](https://www.youtube.com/watch?v=wW9-KuezPp8&t=664s)
Endo does this by encouraging the [Principle of Least Authority](#§pola).

Since most JavaScript libraries receive powerful capabilities from global
objects like `fetch` or modules like `net`, [LavaMoat][] generates reviewable
Expand All @@ -49,20 +40,19 @@ distributed programs easy to program, and easy to reason about integrity.
CapTP frees the programmer from needing to create bespoke communication
protocols over message ports or byte streams.

Endo combines these components to demonstrate their use for a confined plugin
system in the [Endo Pet-name Dæmon](packages/daemon) and its
[CLI](packages/cli).

Please join the conversation on our [Mailing List][SES Strategy Group] and
[Matrix][Endo Matrix].
We record a [weekly conference call][SES Strategy Recordings] with the Hardened
JavaScript engineering community.
Reach out if you would like an ivitation to our **meetings**:

[SES]: packages/ses/README.md
[Handled Promise]: packages/eventual-send/README.md
[CapTP]: packages/captp/README.md#agoriccaptp
[LavaMoat]: https://github.com/LavaMoat/LavaMoat
[POLA]: https://en.wikipedia.org/wiki/Principle_of_least_privilege
[supply chain attacks]: https://en.wikipedia.org/wiki/Supply_chain_attack
[Endo Matrix]: https://matrix.to/#/#endojs:matrix.org
[SES Strategy Group]: https://groups.google.com/g/ses-strategy
[SES Strategy Recordings]: https://www.youtube.com/playlist?list=PLzDw4TTug5O1jzKodRDp3qec8zl88oxGd
- We record a weekly [Endo Sync video call][Endo Sync] .
- We recorded a weekly [SES video call][SES Strategy Recordings] with the
Hardened JavaScript engineering community.
- We now meet weekly with [ECMA TC-39 ECMAScript Technical Committee TG-3
Security Working Group][TG3].

## Ruminations on the Name

Expand All @@ -83,6 +73,24 @@ So, just as "soo-doo" (super user do) and "soo-doh" (like "pseudo") are valid
pronunciations of `sudo`, "en-doh" and "en-doo" are both valid pronunciations of
`endo`.

<a name="§pola"></a>
### Principle of Least Authority

The Principle of Least Authority [(Wikipedia)][PoLA] states that a software
component should only have access to data and resources that enable it to do
its legitimate work.

**PoLA explained in 3 minutes:**
_Opening Statement on SOSP 50th Anniversary Panel_, Mark Miller:

[![Video presentation explaining PoLA in 3 minutes](https://img.youtube.com/vi/br9DwtjqmVI/0.jpg)](https://www.youtube.com/watch?v=br9DwtjqmVI)

**PoLA explained in 15 minutes:**
_Navigating the Attack Surface to achieve a multiplicative reduction in risk_,
Mark Miller:

[![Video presentation explaining PoLA in 15 minutes](https://img.youtube.com/vi/wW9-KuezPp8/0.jpg)](https://www.youtube.com/watch?v=wW9-KuezPp8&t=664s)

### Bug Disclosure

Please help us practice coordinated security bug disclosure, by using the
Expand All @@ -96,9 +104,21 @@ page](https://github.com/Agoric/SES-shim/issues).

Endo and its components are [Apache 2.0 licensed][license-url].

[CapTP]: packages/captp/README.md#agoriccaptp
[Endo Matrix]: https://matrix.to/#/#endojs:matrix.org
[Endo Sync]: https://www.youtube.com/watch?v=tM5NyB7xxYM&list=PLzDw4TTug5O0eUj81Vnkp-mFuI4O0rBnc
[Handled Promise]: packages/eventual-send/README.md
[LavaMoat]: https://github.com/LavaMoat/LavaMoat
[PoLA]: https://en.wikipedia.org/wiki/Principle_of_least_privilege
[SES Proposal]: https://github.com/tc39/proposal-ses
[SES Strategy Group]: https://groups.google.com/g/ses-strategy
[SES Strategy Recordings]: https://www.youtube.com/playlist?list=PLzDw4TTug5O1jzKodRDp3qec8zl88oxGd
[SES]: packages/ses/README.md
[ci-svg]: https://github.com/Agoric/SES-shim/workflows/CI/badge.svg?branch=master
[ci-url]: https://github.com/Agoric/SES-shim/actions?query=workflow%3ACI
[contributing-svg]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg
[contributing-url]: ./CONTRIBUTING.md
[license-image]: https://img.shields.io/badge/License-Apache%202.0-blue.svg
[license-url]: ./LICENSE
[supply chain attacks]: https://en.wikipedia.org/wiki/Supply_chain_attack
[TG3]: https://github.com/tc39/tg3
3 changes: 2 additions & 1 deletion packages/cli/src/commands/adopt.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os from 'os';
import { E } from '@endo/far';
import { withEndoAgent } from '../context.js';
import { parsePetNamePath } from '../pet-name.js';

export const adoptCommand = async ({
messageNumberText,
Expand All @@ -12,5 +13,5 @@ export const adoptCommand = async ({
withEndoAgent(agentNames, { os, process }, async ({ agent }) => {
// TODO less bad number parsing.
const messageNumber = Number(messageNumberText);
await E(agent).adopt(messageNumber, edgeName, name);
await E(agent).adopt(messageNumber, edgeName, parsePetNamePath(name));
});
2 changes: 1 addition & 1 deletion packages/cli/src/commands/eval.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const evalCommand = async ({
source,
codeNames,
petNames,
resultName,
parsePetNamePath(resultName),
);
console.log(result);
});
5 changes: 4 additions & 1 deletion packages/cli/src/commands/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { makeReaderRef } from '@endo/daemon';
import bundleSource from '@endo/bundle-source';

import { withEndoAgent } from '../context.js';
import { parsePetNamePath } from '../pet-name.js';
import { randomHex16 } from '../random.js';

const textEncoder = new TextEncoder();
Expand All @@ -25,6 +26,7 @@ export const install = async ({
let bundleReaderRef;
/** @type {string | undefined} */
let temporaryBundleName;
await null;
if (programPath !== undefined) {
if (bundleName === undefined) {
// TODO alternately, make a temporary session-scoped GC pet store
Expand All @@ -41,6 +43,7 @@ export const install = async ({

await withEndoAgent(agentNames, { os, process }, async ({ agent }) => {
// Prepare a bundle, with the given name.
await null;
if (bundleReaderRef !== undefined) {
await E(agent).storeBlob(bundleReaderRef, bundleName);
}
Expand All @@ -53,7 +56,7 @@ export const install = async ({
)}, $id, $cancelled)`,
['apps', 'bundle', 'powers'],
['APPS', bundleName, powersName],
webletName,
parsePetNamePath(webletName),
);
const webletLocation = await E(weblet).getLocation();
process.stdout.write(`${webletLocation}\n`);
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/commands/mkdir.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ import { parsePetNamePath } from '../pet-name.js';

export const mkdir = async ({ agentNames, directoryPath }) =>
withEndoAgent(agentNames, { os, process }, async ({ agent }) => {
await E(agent).makeDirectory(...parsePetNamePath(directoryPath));
await E(agent).makeDirectory(parsePetNamePath(directoryPath));
});
9 changes: 7 additions & 2 deletions packages/cli/src/commands/remove.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@
import os from 'os';
import { E } from '@endo/far';
import { withEndoAgent } from '../context.js';
import { parsePetNamePath } from '../pet-name.js';

export const remove = async ({ petNames, agentNames }) =>
export const remove = async ({ petNamePaths, agentNames }) =>
withEndoAgent(agentNames, { os, process }, async ({ agent }) =>
Promise.all(petNames.map(petName => E(agent).remove(petName))),
Promise.all(
petNamePaths.map(petNamePath =>
E(agent).remove(...parsePetNamePath(petNamePath)),
),
),
);
7 changes: 6 additions & 1 deletion packages/cli/src/commands/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os from 'os';
import { E } from '@endo/far';
import { withEndoAgent } from '../context.js';
import { parsePetNamePath } from '../pet-name.js';

export const request = async ({
description,
Expand All @@ -10,7 +11,11 @@ export const request = async ({
agentNames,
}) => {
await withEndoAgent(agentNames, { os, process }, async ({ agent }) => {
const result = await E(agent).request(toName, description, resultName);
const result = await E(agent).request(
toName,
description,
parsePetNamePath(resultName),
);
console.log(result);
});
};
9 changes: 7 additions & 2 deletions packages/cli/src/commands/spawn.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
import os from 'os';
import { E } from '@endo/far';
import { withEndoAgent } from '../context.js';
import { parsePetNamePath } from '../pet-name.js';

export const spawn = async ({ petNames, agentNames }) =>
export const spawn = async ({ petNamePaths, agentNames }) =>
withEndoAgent(agentNames, { os, process }, async ({ agent }) =>
Promise.all(petNames.map(petName => E(agent).provideWorker(petName))),
Promise.all(
petNamePaths.map(petNamePath =>
E(agent).provideWorker(parsePetNamePath(petNamePath)),
),
),
);
11 changes: 6 additions & 5 deletions packages/cli/src/endo.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export const main = async rawArgs => {
UNCONFINED: importPath,
name: resultName,
bundle: bundleName,
worker: workerName = 'NEW',
worker: workerName = undefined,
as: agentNames,
powers: powersName = 'NONE',
} = cmd.opts();
Expand Down Expand Up @@ -291,10 +291,10 @@ export const main = async rawArgs => {
.command('remove [names...]')
.description('forget a named value')
.option(...commonOptions.as)
.action(async (petNames, cmd) => {
.action(async (petNamePaths, cmd) => {
const { as: agentNames } = cmd.opts();
const { remove } = await import('./commands/remove.js');
return remove({ petNames, agentNames });
return remove({ petNamePaths, agentNames });
});

program
Expand Down Expand Up @@ -405,10 +405,10 @@ export const main = async rawArgs => {
.command('spawn [names...]')
.description('creates a worker')
.option(...commonOptions.as)
.action(async (petNames, cmd) => {
.action(async (petNamePaths, cmd) => {
const { as: agentNames } = cmd.opts();
const { spawn } = await import('./commands/spawn.js');
return spawn({ petNames, agentNames });
return spawn({ petNamePaths, agentNames });
});

program
Expand Down Expand Up @@ -591,6 +591,7 @@ export const main = async rawArgs => {
.description('erases persistent state and stops if running')
.action(async cmd => {
const { force } = cmd.opts();
await null;
const doPurge =
force ||
/^y(es)?$/u.test(
Expand Down
Loading

0 comments on commit 5eb079d

Please sign in to comment.