Skip to content

Example of overriding Secret with custom implementation #17

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ This repository contains examples of [embedding Observable notebooks](https://ob
| [**custom-fluid-width**](https://github.com/observablehq/examples/tree/main/custom-fluid-width/) | Resize a chart when the window is resized |
| [**custom-fluid-width-and-height**](https://github.com/observablehq/examples/tree/main/custom-fluid-width-and-height/) | Resize a chart when its container is resized |
| [**custom-library**](https://github.com/observablehq/examples/tree/main/custom-library/) | Override the Observable Standard Library |
| [**secret**](https://github.com/observablehq/examples/tree/main/secret) | Override the implementation of Secrets |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| [**secret**](https://github.com/observablehq/examples/tree/main/secret) | Override the implementation of Secrets |
| [**secret**](https://github.com/observablehq/examples/tree/main/secret) | Override the implementation of secrets |

It’s good to capitalize the Secret function, but I’d prefer to keep the term “secrets” lowercase.

| [**standalone**](https://github.com/observablehq/examples/tree/main/standalone/) | Self-host an Observable notebook with no external dependencies |
| [**versioning**](https://github.com/observablehq/examples/tree/main/versioning/) | Embed a specific version of a notebook |
| [**iframe-resize**](https://github.com/observablehq/examples/tree/main/iframe-resize/) | Implementing Embedly’s protocol for Iframes that resize to match their contents |
Expand Down
7 changes: 7 additions & 0 deletions secret/[email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function define(runtime, observer) {
const main = runtime.module();
main.variable(observer()).define(["Secret"], function(Secret){return(
Secret("MY_SECRET_KEY")
)});
return main;
}
19 changes: 19 additions & 0 deletions secret/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Observable Example: Secret

See it live: https://observablehq.github.io/examples/secret

Observable lets you configure [Secrets](https://observablehq.com/@observablehq/secrets). Sensitive variables can be stored outside your code and returned by calling `Secret("MY_SECRET_KEY")`, which might return a password like `"$w0rdf1sh"`. If you publish the notebook, the Secret will throw an error instead of returning a value, so that the Secret is not publicly exposed.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Observable lets you configure [Secrets](https://observablehq.com/@observablehq/secrets). Sensitive variables can be stored outside your code and returned by calling `Secret("MY_SECRET_KEY")`, which might return a password like `"$w0rdf1sh"`. If you publish the notebook, the Secret will throw an error instead of returning a value, so that the Secret is not publicly exposed.
Observable lets you configure [secrets](https://observablehq.com/@observablehq/secrets). Sensitive variables can be stored outside your code and returned by calling `Secret("MY_SECRET_KEY")`, which might return a password like `"$w0rdf1sh"`. If you publish the notebook, calling `Secret` will throw an error instead of returning a value so that the secret is not publicly exposed.


Calling `Secret` will also throw an error if you download the notebook — but sometimes, you might be downloading it to run in your own secure setting where you’d like to set the Secret a different way. This example shows how to use your own implementation of the Secret function to provide things like environment variables or API keys without rewriting your code.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Calling `Secret` will also throw an error if you download the notebook — but sometimes, you might be downloading it to run in your own secure setting where you’d like to set the Secret a different way. This example shows how to use your own implementation of the Secret function to provide things like environment variables or API keys without rewriting your code.
Calling `Secret` will also throw an error if you download the notebook — but sometimes, you might be downloading it to run in your own secure setting where you’d like to set the secret a different way. This example shows how to use your own implementation of `Secret` to provide things like environment variables or API keys without rewriting your code.


In this _insecure_ example, index.html gets Secret values from a hardcoded Map. This should never be used in code that would be seen openly on the client side; if you published this index.html publicly on the Web, anyone could read your hardcoded Secrets.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In this _insecure_ example, index.html gets Secret values from a hardcoded Map. This should never be used in code that would be seen openly on the client side; if you published this index.html publicly on the Web, anyone could read your hardcoded Secrets.
In this _insecure_ example, index.html gets secret values from a hardcoded Map. This should never be used in code that would be seen openly on the client side; if you published this index.html publicly on the Web, anyone could read your hardcoded secrets.


```js
const secrets = new Map([["MY_SECRET_KEY", "$w0rdf1sh"]]);
const Secret = () => key => secrets.get(key);
const runtime = new Runtime(Object.assign(new Library, {Secret}));
```

Note that our `Secret` is a function that returns the function that gets called by the cell; the [Runtime documentation](https://github.com/observablehq/runtime) says:

> If you wish for the value of a builtin to be a function, the builtin must be defined either as a promise that resolves to a function or as a function that returns a function. Builtins may also be defined as generators for dynamic values…
46 changes: 46 additions & 0 deletions secret/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Embedding a notebook that uses a Secret</title>
<link rel="stylesheet" type="text/css" href="./inspector.css">
<style>

body {
max-width: 960px;
margin: 1em auto;
font-family: sans-serif;
}

</style>
<body>

<h1><a href="https://github.com/observablehq/examples">Observable Example</a>: <a href="https://github.com/observablehq/examples/tree/main/secret">Secret</a></h1>

<p>This example demonstrates overriding <a href="https://observablehq.com/@observablehq/secrets">Secrets</a> with your own implementation.</p>

<script type="module">

import define from "./index.js";
import {Runtime, Library, Inspector} from "./runtime.js";

// This is an *insecure* example of how to use your own implementation of the
// built-in Secret function by getting values from a hardcoded Map. Note that
// our `Secret` is a function that returns the function that gets called by the
// cell; the runtime documentation https://github.com/observablehq/runtime says:

// > If you wish for the value of a builtin to be a function, the builtin must
// > be defined either as a promise that resolves to a function or as a function
// > that returns a function. Builtins may also be defined as generators for
// > dynamic values…

const secrets = new Map([["MY_SECRET_KEY", "$w0rdf1sh"]]);
const Secret = () => key => secrets.get(key);

// When we initialize the runtime, we pass it a standard Library object, with
// `Secret` overridden with our custom implementation. Now, when a cell calls
// Secret("MY_SECRET_KEY"), it will return "$w0rdf1sh".

const runtime = new Runtime(Object.assign(new Library, {Secret}));

const main = runtime.module(define, Inspector.into(document.body));

</script>
1 change: 1 addition & 0 deletions secret/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {default} from "./[email protected]";
1 change: 1 addition & 0 deletions secret/inspector.css

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

14 changes: 14 additions & 0 deletions secret/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "9cdbbe083c4d48f4",
"main": "[email protected]",
"version": "9.0.0",
"homepage": "https://observablehq.com/d/9cdbbe083c4d48f4",
"author": {
"name": "tophtest",
"url": "https://observablehq.com/@tophtest"
Comment on lines +7 to +8
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we put this under @observablehq?

},
"type": "module",
"peerDependencies": {
"@observablehq/runtime": "4"
}
}
2 changes: 2 additions & 0 deletions secret/runtime.js

Large diffs are not rendered by default.