env GOPRIVATE='test/main,private.source' garble build exec ./main$exe cmp stderr main.stderr ! binsubstr main$exe 'localName' 'globalConst' 'globalVar' 'globalType' 'valuable information' 'private.source' 'remoteIntReturn' 'intReturn' 'neverInlined' [short] stop # no need to verify this with -short # Check that the program works as expected without garble. go build exec ./main$exe cmp stderr main.stderr binsubstr main$exe 'globalVar' # 'globalType' matches on some, but not all, platforms ! binsubstr main$exe 'localName' 'globalConst' 'remoteIntReturn' 'intReturn' -- extra/go.mod -- module private.source/extra go 1.16 -- extra/extra.go -- package extra func Func() string { return "This is a separate module to obfuscate." } -- go.mod -- module test/main go 1.16 // We include an extra module to obfuscate, included in the same original source // code via a replace directive. require private.source/extra v0.0.0-00010101000000-000000000000 replace private.source/extra => ./extra -- main.go -- package main import ( "go/ast" "private.source/extra" "test/main/sub" ) // This comment contains valuable information. Ensure it's not in the final binary. var V interface{} type T struct { ast.Node *ast.Ident } type Embedded int type Embedding struct { Embedded } type embedded int type embedding struct { embedded } // embedded fields whose type is in the universe scope used to crash garble type EmbeddingUniverseScope struct { error int string } // TODO: test that go:noinline still works without using debugdir //go:noinline func neverInlined() { println("This func is never inlined.") } type EmbeddingOuter struct { EmbeddingInner } type EmbeddingInner struct { SomeField int } func main() { switch V := V.(type) { case int: var _ int = V case nil: println("nil case") } scopesTest() println(extra.Func()) sub.Test() neverInlined() } -- scopes.go -- package main const globalConst = 1 type globalType int var ( globalVar = 1 globalVarTyped globalType = 1 ) func scopesTest() { println(globalVar, globalConst, globalVarTyped) const localNameConst = 1 localNameShort := 4 type localNameType int var ( localNameVar = 5 localNameTypeVar localNameType = 1 ) println(localNameConst, localNameShort, localNameVar, localNameTypeVar, input("input")) } func input(localNameParam string) (localNameReturn string) { return localNameParam } -- sub/names.go -- package sub var someGlobalVar0 = "0" var someGlobalVar1 = "1" var someGlobalVar2 = "2" func Test() { var A, B, C, D, E string noop(A, B, C, D, E) if someGlobalVar0 != "0" || someGlobalVar1 != "1" || someGlobalVar2 != "2"{ panic("name collision detected") } } func noop(...interface{}) {} // Funcs that almost look like test funcs used to make garble panic. func TestFoo(s string) {} func TestBar(*struct{}) {} // If we obfuscate the alias name, we must obfuscate its use here too. type EmbeddingAlias struct { EmbeddedAlias } type EmbeddedAlias = EmbeddedStruct type EmbeddedStruct struct { Foo int } -- main.stderr -- nil case 1 1 1 1 4 5 1 input This is a separate module to obfuscate. This func is never inlined.