Starlarky
VGS edition of Google's safe and hermetically sealed Starlark language
Starlarky is VGS in-house edition of Bazel's hermetically-sealed language created by Google called Starlark. This language is used to run "unsafe" user-submitted code without exposing service at whole to possible attack and/or vulnerabilities. Starlark has Python-like syntax and is created to support same structure of additional libraries. Key differences between Starlark and Python can be found here
Starlarky is presented as a monorepo with different modules
Libstarlark is a maven module, that contains Starlark compiler from bazelbuild This module is being periodically updated from bazelbuild via this script to maintain relevancy.
See more at Libstarlarky README
To build run this command:
mvn versions:set -DnewVersion=<your-version> -pl libstarlark (optional)
mvn clean package -pl libstarlarkLarky is a maven module, that contains VGS additions to Starlark language. Some additions ispired and taken from Copybara
Here are some of them:
- JSR223 script engine
- Annotations to define additional libraries
- Extension modules
To build run this command:
mvn versions:set -DnewVersion=<your-version> -pl larky (optional)
mvn versions:set-property -Dproperty=libstarlark.version -DnewVersion=<larky-version> -pl larky
mvn clean package -pl larkyRunlarky is an example Larky invocation application. It is a picocli command-line application, built as a GraalVM native executable, that runs Larky with input parameters.
To build run this command:
mvn versions:set -DnewVersion=<your-version> -pl runlarky (optional)
mvn versions:set-property -Dproperty=starlarky.version -DnewVersion=<larky-version> -pl runlarky
mvn clean package -pl runlarky -PnativeThis would build larky-runner executable in runlarky/target directory, that can be run from terminal
Run larky-runner with no arguments to get an interactive Larky prompt. It has the same environment as a script run by the runner, so Python builtins and load() of @stdlib, @vendor and @vgs modules work. Use it to try out a snippet or poke at a module before putting it in a script.
Install on Linux (x86-64). Each release from 1.0.0 on attaches a native larky-<version>-linux binary. Download it from the releases page, then:
chmod +x larky-1.0.0-linux
./larky-1.0.0-linuxBuild a native binary on macOS (Apple Silicon). install_graalvm.sh downloads GraalVM into .graalvm, and the native profile builds runlarky/target/larky-runner with it. The native build takes several minutes.
./install_graalvm.sh
JAVA_HOME="$PWD/.graalvm/Contents/Home" mvn -B -q -pl runlarky -am -Pnative -DskipTests package
runlarky/target/larky-runnerOr run it on the JVM, on any OS with Java 21. This skips the native build:
mvn -B -q -pl runlarky -am -DskipTests package dependency:build-classpath -Dmdep.outputFile=target/classpath.txt
java -cp "runlarky/target/runlarky-1.0.0-SNAPSHOT.jar:$(cat runlarky/target/classpath.txt)" \
com.verygood.security.run.LarkyEntrypointBoth print three SLF4J warnings when they start; they're harmless. If Maven can't download a dependency, set up GitHub Packages access first (see Developer setup).
Use it:
Larky interactive interpreter. Type :help for help, :quit or Ctrl-D to exit.
>>> load("@stdlib//base64", "base64")
>>> base64.b64encode(b"hi")
b"aGk="
>>> def add(a, b):
... return a + b
...
>>> add(2, 3)
5
- The value of an expression is printed. A block (
def,if,for) ends at a blank line. - Tab completes names, attributes (
base64.<Tab>) andload()labels. Up and down arrows walk through history, which is kept in~/.larky_history. - Ctrl-C cancels the line you're typing, or stops a running evaluation, without leaving the REPL.
- Commands:
:help,:load <file>(run a.starfile in the session),:reset(forget every binding),:quitor Ctrl-D. - Input can also be piped in. There's no prompt then, and the exit status is 1 if any input failed:
echo 'print(1 + 1)' | larky-runnerprints2.
Script mode (-s, -i, -o, -l, -d) works as before.
Pylarky is pip lib-wrapper for runlarky to make larky calls conveniently from Python.
docker-compose build
docker compose run --rm maven /bin/sh -c "./install_graalvm.sh && ./build-and-test-java.sh"
docker compose run --rm python /bin/sh -c "./build-and-test-python.sh"mvn -Dtest='StdLibTest*' -Dlarky.stdlib_test=test_bytes.star org.apache.maven.plugins:maven-surefire-plugin:3.0.0-M5:test -pl larkyA host that runs a customer's script through the JSR223 engine can pass other files with it in
the LarkyScriptEngine.MODULES engine property (a Map<String, String> of file name to
source); the script loads them by name, e.g. load("vgs_owned", "sign") for vgs_owned.star.
Each loads into its own module. LarkyScriptEngine.CACHE_NAMESPACE (e.g. a tenant ID) keeps
the compiled programs of these files apart per namespace in Larky's cache.
OpaqueModuleExampleTest
ships a module that keeps a vault alias in _KEY_ALIAS and exposes sign(message), which
reveals the key behind the alias and returns an HMAC. Names that start with _ are private to
their file, so load("vgs_owned", "_KEY_ALIAS") fails when the script is compiled with
symbol '_KEY_ALIAS' is private and cannot be imported.
mvn test -pl larky -am -Dtest=OpaqueModuleExampleTest -Dsurefire.failIfNoSpecifiedTests=falseWhat this hides, and what it does not:
- The value stays hidden only while no public function returns it, returns something derived from it that gives it away, or puts it in an error message. A private name is not access control.
- The script can call the public functions with any arguments, as often as it likes: the module is an oracle for whatever they do (here, an HMAC of any message the script chooses).
- The script can call
vault.revealitself on any alias it learns some other way. - Storing a module per tenant, choosing which modules to pass with which script, and keeping tenants apart are up to the host (e.g. the proxy). Larky only loads the files it is given.
Building Starlarky requires JDK 21 or newer and Maven 3.9 or newer; a build of the whole project stops at the start with a message saying so if either is older. With those installed, build and install all modules from the repository root with:
mvn clean installMaven must also be configured to retrieve artifacts from Github.
-
Generate an access token using Github's instructions. The token needs
read:packagesscopes. -
You must enable SSO for verygoodsecurity
-
Place the token in your
~/.m2/settings.xmlfile. For example (look forgithub-usernameandgithub-api-keyto be replaced with your values):
<?xml version='1.0' encoding='us-ascii'?>
<settings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository />
<interactiveMode />
<usePluginRegistry />
<offline />
<pluginGroups />
<servers>
<server>
<id>github</id>
<username>github-username</username>
<password>github-api-key</password>
</server>
</servers>
<mirrors />
<proxies />
<profiles />
<activeProfiles />
</settings>
Release-please plugin manages creation of tag&release.