-
Notifications
You must be signed in to change notification settings - Fork 208
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: Enable enforcement that far must be declared
- Loading branch information
Showing
10 changed files
with
228 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
// @ts-check | ||
/* global globalThis */ | ||
|
||
// Note: Might need to be imported quite early, so this module should | ||
// avoid importing other things. | ||
|
||
const { details: X, quote: q } = assert; | ||
|
||
/** | ||
* JavaScript module semantics resists attempts to parameterize a module's | ||
* initialization behavior. A module initializes in order according to | ||
* the path by which it is first imported, and then the initialized module | ||
* is reused by all the other times it is imported. Compartments give us | ||
* the opportunity to bind the same import name to different imported | ||
* modules, depending on the package/compartment doing the import. Compartments | ||
* also address the difficulty of parameterizing a module's initialization | ||
* logic, but not in a pleasant manner. | ||
* | ||
* A pleasant parameterization would be for a static module to be function-like | ||
* with explicit parameters, and for the parameterization to be like | ||
* calling the static module with parameters in order to derive from it a | ||
* module instance. Compartments instead lets us parameterize the meaning | ||
* of a module instance derived from a static module according to the | ||
* three namespaces provided by the JavaScript semantics, effecting the | ||
* meaning of a module instance. | ||
* * The global variable namespaces. | ||
* * The global scope, aliased to properties of the global object. | ||
* This is necessarily compartment-wide, and therefore in our | ||
* recommened usage pattern, packages-wide. | ||
* * The global lexical scope. The SES-shim compartments supports | ||
* these both compartment-wide as well as per-module. But it is | ||
* not yet clear what we will propose in the Compartment proposal. | ||
* * The import namespace. | ||
* * The host hooks. | ||
* | ||
* This `environment-options.js` module looks for a setting of of an | ||
* `optionName` parameter rooted in the global scope. If follows the Node | ||
* precedent for finding Unix environment variable settings, looking for a | ||
* global `process` object holding an `env` object, | ||
* optionally holding a property named for the `optionName` whose value is the | ||
* configuration setting of that option. For example, for the optionName | ||
* `ALLOW_IMPLICIT_REMOTABLES` it would look in | ||
* `globalThis.process.env.ALLOW_IMPLICIT_REMOTABLES`. | ||
* | ||
* If setting is either absent or `undefined`, that indicates that | ||
* this configuration option should have its default behavior, whatever that is. | ||
* Otherwise, reflecting Unix environment variables, the setting must be a | ||
* string. This also helps ensure that this channel is used only to pass data, | ||
* not authority beyond the ability to read this global state. | ||
* | ||
* The current placement of this `environment-options.js` module in the | ||
* `@agoric/marshal` package is a stopgap measure. | ||
* TODO the intention is to migrate it into Endo, and to migrate all our | ||
* direct uses of `process.env` for configuration parameters to use it | ||
* instead. | ||
* | ||
* Even after that migration, this module will still not be used for | ||
* `LOCKDOWN_OPTIONS` itself, since that must happen before `lockdown`, | ||
* whereas this module must initialize after `lockdown`. | ||
* | ||
* @param {string} optionName | ||
* @param {string=} defaultSetting | ||
*/ | ||
export const getEnvironmentOption = ( | ||
optionName, | ||
defaultSetting = undefined, | ||
) => { | ||
assert.typeof( | ||
optionName, | ||
'string', | ||
X`Environment option name ${q(optionName)} must be a string.`, | ||
); | ||
assert( | ||
defaultSetting === undefined || typeof defaultSetting === 'string', | ||
X`Environment option default setting ${q( | ||
defaultSetting, | ||
)}, if present, must be a string.`, | ||
); | ||
|
||
let setting = defaultSetting; | ||
const globalProcess = globalThis.process; | ||
if (typeof process === 'object' && typeof globalProcess.env === 'object') { | ||
if (optionName in globalProcess.env) { | ||
console.log( | ||
`Environment options sniffed and found an apparent ${q( | ||
optionName, | ||
)} environment variable.'\n`, | ||
); | ||
setting = globalProcess.env[optionName]; | ||
} | ||
} | ||
assert( | ||
setting === undefined || typeof setting === 'string', | ||
X`Environment option value ${q(setting)}, if present, must be a string.`, | ||
); | ||
return setting; | ||
}; | ||
harden(getEnvironmentOption); | ||
|
||
/** | ||
* Set `globalThis.process.env[optionName]` to `setting`. | ||
* | ||
* This function takes care of the complexity that `process` may or may not | ||
* already exist, `process.env` may or may not already exist, and if both | ||
* exist, this function should mutate only this one property setting, minimizing | ||
* other damage to a shared `globalThis.process.env`. | ||
* | ||
* @param {string} optionName | ||
* @param {string=} setting | ||
*/ | ||
export const setEnvironmentOption = (optionName, setting) => { | ||
assert.typeof(optionName, 'string'); | ||
assert(setting === undefined || typeof setting === 'string'); | ||
if (!('process' in globalThis)) { | ||
// @ts-ignore TS assumes this is the Node process object. | ||
globalThis.process = {}; | ||
} | ||
const globalProcess = globalThis.process; | ||
assert.typeof(globalProcess, 'object'); | ||
if (!('env' in globalProcess)) { | ||
// @ts-ignore TS assumes this is the Node process object. | ||
globalProcess.env = {}; | ||
} | ||
const env = globalProcess.env; | ||
assert.typeof(env, 'object'); | ||
if (optionName in env) { | ||
console.log(`Overwriting apparent environment variable ${q(optionName)}`); | ||
} | ||
env[optionName] = setting; | ||
}; | ||
harden(setEnvironmentOption); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// @ts-check | ||
|
||
// This one is designed to be imported this early | ||
import { setEnvironmentOption } from '../src/helpers/environment-options.js'; | ||
|
||
// Import this module early, so it initializes before any module whose | ||
// initialization reads this option. | ||
|
||
setEnvironmentOption('ALLOW_IMPLICIT_REMOTABLES', 'true'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// @ts-check | ||
|
||
// This one is designed to be imported this early | ||
import { setEnvironmentOption } from '../src/helpers/environment-options.js'; | ||
|
||
// Import this module early, so it initializes before any module whose | ||
// initialization reads this option. | ||
|
||
setEnvironmentOption('ALLOW_IMPLICIT_REMOTABLES', undefined); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// @ts-check | ||
|
||
// This one is designed to be imported this early | ||
import { setEnvironmentOption } from '../src/helpers/environment-options.js'; | ||
|
||
// Import this module early, so it initializes before any module whose | ||
// initialization reads this option. | ||
|
||
setEnvironmentOption('ALLOW_IMPLICIT_REMOTABLES', 'false'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// @ts-check | ||
|
||
import { test } from './prepare-test-env-ava.js'; | ||
// Import early, before remotable.js might initialize. | ||
import './allow_implicit_remotables.js'; | ||
|
||
import { passStyleOf } from '../src/passStyleOf.js'; | ||
|
||
test('environment options', t => { | ||
t.notThrows(() => passStyleOf(harden({ toString: () => 'foo' }))); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// @ts-check | ||
|
||
import { test } from './prepare-test-env-ava.js'; | ||
// Import early, before remotable.js might initialize. | ||
import './default_implicit_remotables.js'; | ||
|
||
import { passStyleOf } from '../src/passStyleOf.js'; | ||
import { ALLOW_IMPLICIT_REMOTABLES } from '../src/helpers/remotable.js'; | ||
|
||
// Whatever ALLOW_IMPLICIT_REMOTABLES defaults to, ensure that still works. | ||
|
||
test('environment options', t => { | ||
if (ALLOW_IMPLICIT_REMOTABLES) { | ||
t.notThrows(() => passStyleOf(harden({ toString: () => 'foo' }))); | ||
} else { | ||
t.throws(() => passStyleOf(harden({ toString: () => 'foo' })), { | ||
message: /Remotables must be explicitly declared/, | ||
}); | ||
} | ||
}); |
13 changes: 13 additions & 0 deletions
13
packages/marshal/test/test-disallow-implicit-remotables.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// @ts-check | ||
|
||
import { test } from './prepare-test-env-ava.js'; | ||
// Import early, before remotable.js might initialize. | ||
import './disallow_implicit_remotables.js'; | ||
|
||
import { passStyleOf } from '../src/passStyleOf.js'; | ||
|
||
test('environment options', t => { | ||
t.throws(() => passStyleOf(harden({ toString: () => 'foo' })), { | ||
message: /Remotables must be explicitly declared/, | ||
}); | ||
}); |
18 changes: 18 additions & 0 deletions
18
packages/marshal/test/test-existing-implicit-remotables.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// @ts-check | ||
|
||
import { test } from './prepare-test-env-ava.js'; | ||
import { passStyleOf } from '../src/passStyleOf.js'; | ||
import { ALLOW_IMPLICIT_REMOTABLES } from '../src/helpers/remotable.js'; | ||
|
||
// Whatever ALLOW_IMPLICIT_REMOTABLES is set to in the current test | ||
// environment, ensure that still works. | ||
|
||
test('environment options', t => { | ||
if (ALLOW_IMPLICIT_REMOTABLES) { | ||
t.notThrows(() => passStyleOf(harden({ toString: () => 'foo' }))); | ||
} else { | ||
t.throws(() => passStyleOf(harden({ toString: () => 'foo' })), { | ||
message: /Remotables must be explicitly declared/, | ||
}); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters