Gopherscript is a secure and minimal scripting language written in Go.

Gopherscript

Gopherscript is a secure scripting/configuration language written in Go. It features a fined-grain permission system and enforces a strong isolation of dependencies. Gopherscript is not production ready yet : if you find a bug or want to suggest a feature create an issue please ! Expect breaking changes.

Join the official community on Revolt.

image

Security & Minimalism

  • The codebase is small on purpose (a single Go file with less than 8K lines and only std lib dependencies). See Implementation.
  • The default global scope has ZERO variables/functions and there are no "builtin modules" to import. (only add what you need from Golang)
  • A strict but extensive permission system allows you to precisely control what is allowed (almost no permissions by default). For more details go to the permission section.
  • Paths, path patterns, URLs are literals and dynamic paths are only possible as path expressions. You cannot create them from strings at runtime ! That facilitates the listing of permissions and helps static analysis.
  • Properties cannot be accessed with a dynamic name ( $obj[$name] ), only Go functions that are passed objects in can (you have to trust them anyway).
  • In a general way some features will be added (or refused) to limit code obfuscation.

If you find Gopherscript too restrictive don't worry ! A lax mode might be introduced in the future.

Have a look at the features section and the wiki !

Installation & Usage

You can use the gos executable to execute scripts or launch a REPL:

go install github.com/debloat-dev/Gopherscript/cmd/[email protected]

See the documentation here. You can also use Gopherscript as a library and only add whay you need to the global scope (see the example further below).

Editor support

If you use VSCode you can install the extension of ID xbsd.gopherscript . If you are a NeoVim user, check this repo please.

Example

Example of using Gopherscript as a library from Golang:
package main

import (
	gos "github.com/debloat-dev/Gopherscript"
	"log"
)

type User struct {
	Name string
}

func main() {
   	//we create a Context that contains the granted permissions
	grantedPerms := []gos.Permission{
		gos.GlobalVarPermission{gos.UsePerm, "*"},
	}
	ctx := gos.NewContext(grantedPerms, nil)

    	//we create the initial state with the globals we want to expose
    	//the state can be re used several times (and with different modules)
	state := gos.NewState(ctx, map[string]interface{}{
		"makeUser": func(ctx *gos.Context) User {
			return User{Name: "Bar"}
		},
	})

	mod, err := gos.ParseAndCheckModule(`
            # permissions must be requested at the top of the file AND granted
            require {
                use: {globals: "*"} 
            }
            a = 1
            user = makeUser()
            return [
                ($a + 2),
                $user.Name
            ]
        `, "")
	
	if err != nil {
		log.Panicln(err)
	}

	//we execute the script
	res, err := gos.Eval(mod, state)
	if err != nil {
		log.Panicln(err)
	}

	log.Printf("%#v", res)
}

You can learn more about the interactions between Gopherscript and Golang here.

Features

The most important features are described in this section. If you want to learn Gopherscript or want to know more details about specific features you can go on the wiki.

Permissions

Required permissions are specified at the top of each module (file).

image

There are several permission kinds: Create, Update, Read, Delete, Use, Consume, Provide. Some permission types are already provided: FilesystemPermission, HttpPermission, StackPermission, GlobalVarPermission. You can specify your own permissions by implementing the Permission interface (Golang).

type Permission interface {
	Kind() PermissionKind
	Includes(Permission) bool
}

Gopherscript also provides limitations to prevent a script to take all resources. In the example below writing to the filesystem is limited to 100 kB/s.

require {
    
    [...]

    limits: {
        "fs/write": 100kB/s
    }
}

Special literals & expressions

# Path literals
/home/user/
./file.json

# Path expressions
/home/user/$dirpath$

# Path patterns support basic globbing (*, [set], ?) and prefixing (not both at the same time).
./data/*.json
/app/logs/...
/app/*/...     		# invalid (this might be allowed in the future though)

# HTTP host literals
https://example.com
https://example.com:443

# HTTP host pattern literals
https://*               # any HTTPS host
https://*.com           # any domain with .com as TLD, will not match against subdomains
https://*.example.com   # any subdomain of example.com

# URL literals
https://example.com/
https://example.com/index.html
https://localhost/

# URL expressions
https://example.com/users/$id$

# URL pattern literals (only prefix patterns supported)
https://example.com/users/...

Quantity literals

10s		# time.Duration
10ms		# time.Duration
10%		# 0.10

sleep 100ms

Imports

Syntax:

import <varname> <url> <file-content-sha256>  { <global variables> } allow { <permission> }

Importing a module is like executing a script with the passed globals and granted permissions.

# content of https://example.com/return_1.gos
return 1

Script:

image

Routines

Routines are mainly used for concurrent work and isolation. Each routine has its own goroutine and state.

Syntax for spawning routines:

$routine = sr [group] <globals> <module | call | variable>

Call (all permissions are inherited).

$routine = sr nil f()

Embedded module:

image

You can wait for the routine's result by calling the WaitResult method:

$result = $routine.WaitResult()!

Routines can optionally be part of a "routine group" that allows easier control of multiple routines. The group variable is defined (and updated) when the spawn expression is evaluated.

for (1 .. 10) {
    sr req_group nil read(https://debloat.dev/fakeapp/users)!
}

$results = $req_group.WaitAllResults()!

For more details about the different features you can read the repository's wiki.

Implementation

  • Why use a tree walk interpreter instead of a bytecode interpreter ?
    -> Tree walk interpreters are slower but simpler : that means less bugs and vulnerabilities. A Gopherscript implementation that uses a bytecode interpreter might be developed in the future though.

Executables

When something tries to do too many things it becomes impossible to understand for the average developper. That makes audits and customization harder. Goperscript aims to have a different model. Depending on the features you need, you install one one more executables that try to do one thing well without uncessary bloat (each one providing specific globals to Gophercript).

Owner
Debloat
Debloat your stack, one component at a time. Join the community at https://app.revolt.chat/invite/cJQPeQkc !
Debloat
Similar Resources

A minimal Crossplane Provider that is meant to be used as a template for implementing new Providers

provider-template provider-template is a minimal Crossplane Provider that is meant to be used as a template for implementing new Providers. It comes w

Jan 16, 2022

LTF is a minimal, transparent Terraform wrapper. It makes Terraform projects easier to work with.

LTF Status: alpha LTF is a minimal, transparent Terraform wrapper. It makes Terraform projects easier to work with. In standard Terraform projects, th

Nov 19, 2022

Open Service Mesh (OSM) is a lightweight, extensible, cloud native service mesh that allows users to uniformly manage, secure, and get out-of-the-box observability features for highly dynamic microservice environments.

Open Service Mesh (OSM) is a lightweight, extensible, cloud native service mesh that allows users to uniformly manage, secure, and get out-of-the-box observability features for highly dynamic microservice environments.

Open Service Mesh (OSM) Open Service Mesh (OSM) is a lightweight, extensible, Cloud Native service mesh that allows users to uniformly manage, secure,

Jan 2, 2023

Secure Edge Networking Based On Kubernetes And KubeEdge.

Secure Edge Networking Based On Kubernetes And KubeEdge.

What is FabEdge FabEdge is an open source edge networking solution based on kubernetes and kubeedge. It solves the problems including complex network

Jan 3, 2023

Becca - A simple dynamic language for exploring language design

Becca A simple dynamic language for exploring language design What is Becca Becc

Aug 15, 2022

Secure Distributed Thanos Deployment using an Observability Cluster

Atlas Status: BETA - I don't expect breaking changes, but still possible. Atlas, forced by Zeus to support the heavens and the skies on his shoulders.

Jun 11, 2022

A template repository to quickly scaffold a Kubewarden policy written with Go language

go-policy-template This is a template repository that can be used to to quickly scaffold a Kubewarden policy written with Go language. Don't forget to

Sep 7, 2022

A very simple, silly little kubectl plugin / utility that guesses which language an application running in a kubernetes pod was written in.

A very simple, silly little kubectl plugin / utility that guesses which language an application running in a kubernetes pod was written in.

Mar 9, 2022

Common Expression Language -- specification and binary representation

The Common Expression Language (CEL) implements common semantics for expression evaluation, enabling different applications to more easily interoperate.

Jan 8, 2023
Gola is a Golang tool for automated scripting purpose

Gola Gola is a Golang tool for automated scripting purpose. How To Install You can find the install script here. Example Configuration commands: - n

Aug 12, 2022
Deploy, manage, and secure applications and resources across multiple clusters using CloudFormation and Shipa

CloudFormation provider Deploy, secure, and manage applications across multiple clusters using CloudFormation and Shipa. Development environment setup

Feb 12, 2022
[WIP] Cheap, portable and secure NAS based on the Raspberry Pi Zero - with encryption, backups, and more

PortaDisk - Affordable Raspberry Pi Portable & Secure NAS Project Project Status: Early work in progress. web-unlock is still not ready for production

Nov 23, 2022
Grafana Tempo is a high volume, minimal dependency distributed tracing backend.
Grafana Tempo is a high volume, minimal dependency distributed tracing backend.

Grafana Tempo is an open source, easy-to-use and high-scale distributed tracing backend. Tempo is cost-efficient, requiring only object storage to ope

Jan 8, 2023
Kubedock is a minimal implementation of the docker api that will orchestrate containers on a Kubernetes cluster, rather than running containers locally.

Kubedock Kubedock is an minimal implementation of the docker api that will orchestrate containers on a kubernetes cluster, rather than running contain

Nov 11, 2022
Hassle-free minimal CI/CD for git repositories with docker or docker-compose projects.
Hassle-free minimal CI/CD for git repositories with docker or docker-compose projects.

GIT-PIPE Hassle-free minimal CI/CD for git repos for docker-based projects. Features: zero configuration for repos by default automatic encrypted back

Sep 23, 2022
Truly Minimal Linux Distribution for Containers

Statesman Statesman is a minimal Linux distribution, running from memory, that has just enough functionality to run OCI-compatible containers. Rationa

Nov 12, 2021
A minimal Go project with user authentication ready out of the box. All frontend assets should be less than 100 kB on every page load

Golang Base Project A minimal Golang project with user authentication ready out of the box. All frontend assets should be less than 100 kB on every pa

Jan 1, 2023
A minimal Crossplane Provider For Golang

provider-template provider-template is a minimal Crossplane Provider that is mea

Dec 19, 2021
Package pinentry provides a minimal client to GnuPG's pinentry

go-pinentry-minimal Package pinentry provides a minimal client to GnuPG's pinentry, which only depends on Go's standard library. It is a fork of githu

Nov 20, 2022