{"id":28396201,"url":"https://github.com/ssbc/go-ssb","last_synced_at":"2025-10-19T18:13:42.425Z","repository":{"id":34479611,"uuid":"137509423","full_name":"ssbc/go-ssb","owner":"ssbc","description":"Go implementation of ssb (work in progress!)","archived":false,"fork":false,"pushed_at":"2023-06-23T18:25:38.000Z","size":15026,"stargazers_count":165,"open_issues_count":58,"forks_count":23,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-08-21T12:43:02.684Z","etag":null,"topics":["go","golang","secure-scuttlebutt","ssb"],"latest_commit_sha":null,"homepage":"https://scuttlebutt.nz","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ssbc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSES/AGPL-3.0-only.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null}},"created_at":"2018-06-15T16:23:59.000Z","updated_at":"2025-06-04T11:55:14.000Z","dependencies_parsed_at":"2024-03-17T02:15:45.846Z","dependency_job_id":"fd243110-2720-4a2c-a182-9b9655786e6a","html_url":"https://github.com/ssbc/go-ssb","commit_stats":null,"previous_names":["cryptoscope/ssb","cryptoscope/sbot"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/ssbc/go-ssb","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssbc%2Fgo-ssb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssbc%2Fgo-ssb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssbc%2Fgo-ssb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssbc%2Fgo-ssb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ssbc","download_url":"https://codeload.github.com/ssbc/go-ssb/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssbc%2Fgo-ssb/sbom","scorecard":{"id":310317,"data":{"date":"2025-08-11","repo":{"name":"github.com/ssbc/go-ssb","commit":"d6db27d1852d5edff9c7e07d2a3419fe6b11a8db"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.7,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/go.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":10,"reason":"all changesets reviewed","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Pinned-Dependencies","score":4,"reason":"dependency not pinned by hash detected -- score normalized to 4","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/ssbc/go-ssb/go.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/ssbc/go-ssb/go.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:29: update your workflow using https://app.stepsecurity.io/secureworkflow/ssbc/go-ssb/go.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:43: update your workflow using https://app.stepsecurity.io/secureworkflow/ssbc/go-ssb/go.yml/master?enable=pin","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   1 out of   1 goCommand dependencies pinned","Info:   2 out of   2 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSES/AGPL-3.0-only.txt:0","Info: FSF or OSI recognized license: GNU Affero General Public License v3.0 only: LICENSES/AGPL-3.0-only.txt:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"22 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2025-3372 / GHSA-6wxm-mpqj-6jpf","Warn: Project is vulnerable to: GO-2023-2402 / GHSA-45x7-px36-x8w8","Warn: Project is vulnerable to: GO-2024-3321 / GHSA-v778-237x-gjrc","Warn: Project is vulnerable to: GO-2025-3487 / GHSA-hcg3-q754-cr77","Warn: Project is vulnerable to: GO-2022-1144 / GHSA-xrjj-mj9h-534m","Warn: Project is vulnerable to: GO-2023-1571 / GHSA-vvpx-j8f3-3w6h","Warn: Project is vulnerable to: GO-2023-1988 / GHSA-2wrh-6pvc-2jm9","Warn: Project is vulnerable to: GO-2023-2102 / GHSA-4374-p667-p6c8","Warn: Project is vulnerable to: GHSA-qppj-fm5r-hxr3","Warn: Project is vulnerable to: GO-2024-2687 / GHSA-4v7x-pqxf-cx7m","Warn: Project is vulnerable to: GO-2024-3333","Warn: Project is vulnerable to: GO-2025-3503 / GHSA-qxp5-gwg8-xv66","Warn: Project is vulnerable to: GO-2025-3595 / GHSA-vvgc-356p-c3xw","Warn: Project is vulnerable to: GO-2024-2611 / GHSA-8r3f-844c-mc37","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-qqgx-2p2h-9c37","Warn: Project is vulnerable to: GHSA-78xj-cgh5-2h22","Warn: Project is vulnerable to: GHSA-2p57-rm9w-gvfp","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-17T23:04:37.876Z","repository_id":34479611,"created_at":"2025-08-17T23:04:37.876Z","updated_at":"2025-08-17T23:04:37.876Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273051864,"owners_count":25037074,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-31T02:00:09.071Z","response_time":79,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","secure-scuttlebutt","ssb"],"created_at":"2025-05-31T21:37:18.856Z","updated_at":"2025-10-19T18:13:37.384Z","avatar_url":"https://github.com/ssbc.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--\nSPDX-FileCopyrightText: 2021 The Go-SSB Authors\n\nSPDX-License-Identifier: MIT\n--\u003e\n\n\u003ch1 align=\"center\"\u003eGo-SSB\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg height=\"170px\" src=\"./docs/icon.png\" alt=\"hermit gopher with a shell and crab hands\"\u003e\n\u003c/p\u003e\n\n[![GoDoc](https://godoc.org/github.com/ssbc/go-ssb?status.svg)](https://godoc.org/github.com/ssbc/go-ssb) [![Go Report Card](https://goreportcard.com/badge/github.com/ssbc/go-ssb)](https://goreportcard.com/report/github.com/ssbc/go-ssb) ![Github Actions](https://github.com/ssbc/go-ssb/actions/workflows/go.yml/badge.svg) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![REUSE status](https://api.reuse.software/badge/github.com/ssbc/go-ssb)](https://api.reuse.software/info/github.com/ssbc/go-ssb)\n\n\u003e **WARNING**: Project is still in alpha, backwards incompatible changes will be made.\n\nA full-stack implementation of [secure-scuttlebutt](https://www.scuttlebutt.nz) using the [Go](https://golang.org) programming language.\n\nIf you encounter a bug, please refer to our [public issue tracker](https://github.com/ssbc/go-ssb/issues).\n\nSee the [FAQ](./docs/faq.md) for more. See [this project](https://github.com/orgs/ssbc/projects/2) for current focus.\n\n### Developing\n\nWant to contribute patches to go-ssb? Read the [developer documentation](https://dev.scuttlebutt.nz/#/golang/) hosted at [dev.scuttlebutt.nz](https://dev.scuttlebutt.nz/#/golang/). If you have a large change you want to make, [reach out](#contact) first and we'll together make sure that the resulting PR will be accepted :black_heart:\n\n## Server Features\n\n* [x] Follow-graph implementation (based on [gonum](https://www.gonum.org)) to authorize incoming connections\n* [x] [Blobs](https://ssbc.github.io/scuttlebutt-protocol-guide/#blobs) store and replication\n* [x] Publishing new messages to the log\n* [x] _Legacy_ feed [replication](https://ssbc.github.io/scuttlebutt-protocol-guide/#createHistoryStream)\n* [x] [Epidemic Broadcast Trees (EBT)](https://github.com/dominictarr/epidemic-broadcast-trees) feed replication in beta (use `go-sbot -enable-ebt`)\n* [x] Invite mechanics ([peer-invites](https://github.com/ssbc/ssb-peer-invites) partially done, too. See [Issue 45](https://github.com/ssbc/go-ssb/issues/45) for more.)\n\n## Installation\n\nYou can install the project using Golang's [install command](https://golang.org/cmd/go/#hdr-Compile_and_install_packages_and_dependencies) which will place the commands into the directory pointed to by the GOBIN environment variable.\n\n```bash\ngit clone https://github.com/ssbc/go-ssb\ncd go-ssb\ngo install ./cmd/go-sbot\ngo install ./cmd/sbotcli\n```\n\nRequirements:\n\n  - [Golang](https://www.golang.org) version 1.17 or higher\n\n## Running `go-sbot`\n\nThe tool in `cmd/go-sbot` is similar to [ssb-server](https://github.com/ssbc/ssb-server) (previously called scuttlebot or sbot for short).\n\nSee the [quick start](./docs/quick-start.md) document for a walkthrough and getting started tour. You may also be interested in the ways you can configure a running `go-sbot`, see the [configuration guide](./docs/config.md).\n\n## Bootstrapping from an existing key-pair\n\nIf you have an existing feed with published `contact` messages, you can just resync it from another go or js server. To get this going you copy the key-pair (`$HOME/.ssb/secret` by default) to `$HOME/.ssb-go/secret`, start the program and connect to the server (using the [multiserver address format](https://github.com/ssbc/multiserver/#address-format)).\n\n```bash\nmkdir $HOME/.ssb-go\ncp $HOME/.ssb/secret $HOME/.ssb-go\ngo-sbot \u0026\nsbotcli connect \"net:some.ho.st:8008~shs:SomeActuallyValidPubKey=\"\n```\n\n## Publishing\n\nThis currently constructs _legacy_ SSB messages, that _still_ have the signature inside the signed value:\n\n```json\n{\n  \"key\": \"%EMr6LTquV6Y8qkSaQ96ncL6oymbx4IddLdQKVGqYgGI=.sha256\",\n  \"value\": {\n    \"previous\": \"%rkJMoEspdU75c1RpGbwjEH7eZxM/PJPFubpZTtynhsg=.sha256\",\n    \"author\": \"@iL6NzQoOLFP18pCpprkbY80DMtiG4JFFtVSVUaoGsOQ=.ed25519\",\n    \"sequence\": 793,\n    \"timestamp\": 1457694632215,\n    \"hash\": \"sha256\",\n    \"content\": {\n      \"type\": \"post\",\n      \"text\": \"@dust \\n\u003e this feels like the cultural opposite of self-dogfooding, and naturally, leaves a bad taste in my mouth \\n \\n\\\"This\\\" meaning this thread? Or something in particular in this thread? And if this thread or something in it, how so? I don't want to leave a bad taste in your mouth.\",\n      \"root\": \"%I3yWHMF2kqC7fLZrC8FB+Kuu/6MQZIKzJGIjR3fVv9g=.sha256\",\n      \"branch\": \"%cNJgO+1R4ci/jgTup4LLACoaKZRtYtsO7BzRCDJh6Gg=.sha256\",\n      \"mentions\": [\n        {\n          \"link\": \"@/02iw6SFEPIHl8nMkYSwcCgRWxiG6VP547Wcp1NW8Bo=.ed25519\",\n          \"name\": \"dust\"\n        }\n      ],\n      \"channel\": \"patchwork-dev\"\n    },\n    \"signature\": \"bbjj+zyNubLNEV+hhUf6Of4KYOlQBavQnvdW9rF2nKqTHQTBiFBnRehfveCft3OGSIIr4VgD4ePICCTlBuTdAg==.sig.ed25519\"\n  },\n  \"timestamp\": 1550074432723.0059\n}\n```\n\nThe problem with this (for Go and others) is removing the `signature` field from `value` without changing any of the values or field ordering of the object, which is required to compute the exact same bytes that were used for creating the signature. Signing JSON was a bad idea. There is also other problems around this (like producing the same byte/string encoding for floats that v8 produces) and a new, canonical format is badly needed.\n\nWhat you are free to input is the `content` object, the rest is filled in for you. The author is determined by the keypair used by go-sbot. Multiple identities are supported through the API.\n\n### Over muxrpc\n\ngo-sbot also exposes the same async [publish](https://scuttlebot.io/apis/scuttlebot/ssb.html#publish-async) method that ssb-server has. So you can also use it with ssb-client!\n\n### Through Go API\n\nTo do this programatically in go, you construct a [margaret.Log](https://godoc.org/go.cryptoscope.co/margaret#Log) using `multilogs.OpenPublishLog` ([godoc](https://godoc.org/github.com/ssbc/go-ssb/multilogs#OpenPublishLog)) that publishes the content portion you `Append()` to it the feed of the keypair.\n\nExample:\n\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"fmt\"\n\n\t\"github.com/ssbc/go-ssb\"\n\t\"github.com/ssbc/go-ssb/multilogs\"\n\t\"github.com/ssbc/go-ssb/sbot\"\n)\n\nfunc main() {\n\tsbot, err := sbot.New()\n\tcheck(err)\n\n\tpublish, err := multilogs.OpenPublishLog(sbot.ReceiveLog, sbot.UserFeeds, *sbot.KeyPair)\n\tcheck(err)\n\n\talice, err := refs.ParseFeedRef(\"@alicesKeyInActualBase64Bytes.ed25519\")\n\tcheck(err)\n\n\tvar someMsgs = []interface{}{\n\t\tmap[string]interface{}{\n\t\t\t\"type\":  \"about\",\n\t\t\t\"about\": sbot.KeyPair.ID().Ref(),\n\t\t\t\"name\":  \"my user\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"type\":      \"contact\",\n\t\t\t\"contact\":   alice.Ref(),\n\t\t\t\"following\": true,\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"type\": \"post\",\n\t\t\t\"text\": `# hello world!`,\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"type\":  \"about\",\n\t\t\t\"about\": alice.Ref(),\n\t\t\t\"name\":  \"test alice\",\n\t\t},\n\t}\n\tfor i, msg := range someMsgs {\n\t\tnewSeq, err := publish.Append(msg)\n\t\tcheck(fmt.Errorf(\"failed to publish test message %d: %w\", i, err))\n\t\tlog.Println(\"new message:\", newSeq)\n\t}\n\n\terr = sbot.Close()\n\tcheck(err)\n}\n\nfunc check(err error) {\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\n### `sbotcli`\n\nHas some commands to publish frequently used messages like `post`, `vote` and `contact`:\n\n```bash\nsbotcli publish contact --following '@p13zSAiOpguI9nsawkGijsnMfWmFd5rlUNpzekEE+vI=.ed25519'\nsbotcli publish contact --blocking '@p13zSAiOpguI9nsawkGijsnMfWmFd5rlUNpzekEE+vI=.ed25519'\nsbotcli publish about --name \"cryptix\" '@p13zSAiOpguI9nsawkGijsnMfWmFd5rlUNpzekEE+vI=.ed25519'\n```\n\nThey all support passing multiple `--recps` flags to publish private messages as well:\n```bash\nsbotcli publish post --recps \"@key1\" --recps \"@key2\" \"what's up?\"\n```\n\nFor more dynamic use, you can also just pipe JSON into stdin:\n```bash\ncat some.json | sbotcli publish raw\n```\n\n## Building\n\nThere are two binary executable in this project that are useful right now, both located in the `cmd` folder. `go-sbot` is the database server, handling incoming connections and supplying replication to other peers. `sbotcli` is a command line interface to query feeds and instruct actions like _connect to X_. This also works against the JS implementation.\n\nIf you _just_ want to build the server and play without contributing to the code (and are using a recent go version \u003e 1.17), you can do this:\n\n```bash\n# clone the repo\ngit clone https://github.com/ssbc/go-ssb\n# go into the servers folder\ncd go-ssb/cmd/go-sbot\n# build the binary (also fetches pinned dependencies)\ngo build -v -i\n# test the executable works by printing it's help listing\n./go-sbot -h\n# (optional) install it somwhere on your $PATH\nsudo cp go-sbot /usr/local/bin\n```\n\nIf you want to hack on the other dependencies of the stack, you can use the `replace` statement.\n\nE.g. for hacking on a locally cloned copy of `go-muxrpc`, you'd do:\n\n```diff\ndiff --git a/go.mod b/go.mod\nindex c4d475f..51c2757 100644\n--- a/go.mod\n+++ b/go.mod\n@@ -6,6 +6,8 @@ module github.com/ssbc/go-ssb\n\n+replace github.com/ssbc/go-muxrpc/v2 =\u003e ./../go-muxrpc\n+\n```\n\nWhich points the new build of `go-sbot`/`sbotcli` to use your local copy of `go-muxrpc`.\n\n## Testing\n\nOnce you have configured your environment set up to build the binaries, you can also run the tests. We have unit tests for most of the modules, most importantly `message`, `blobstore` and the replication plugins (`gossip` and `blobs`). There are also interoperability tests with the nodejs implementation (this requires recent versions of [node and npm](http://nodejs.org)).\n\n```bash\n$ go test -v ./message\n2019/01/08 12:21:55 loaded 236 messages from testdata.zip\n=== RUN   TestPreserveOrder\n--- PASS: TestPreserveOrder (0.00s)\n=== RUN   TestComparePreserve\n--- PASS: TestComparePreserve (0.02s)\n=== RUN   TestExtractSignature\n--- PASS: TestExtractSignature (0.00s)\n=== RUN   TestStripSignature\n--- PASS: TestStripSignature (0.00s)\n=== RUN   TestUnicodeFind\n--- PASS: TestUnicodeFind (0.00s)\n=== RUN   TestInternalV8String\n--- PASS: TestInternalV8String (0.00s)\n=== RUN   TestSignatureVerify\n--- PASS: TestSignatureVerify (0.06s)\n=== RUN   TestVerify\n--- PASS: TestVerify (0.06s)\n=== RUN   TestVerifyBugs\n--- PASS: TestVerifyBugs (0.00s)\nPASS\nok  \tgithub.com/ssbc/go-ssb/message\t0.180s\n```\n\nIf you encounter a feed that can't be validated with our code, there is a `encode_test.js` script to create the `testdata.zip` from a local sbot. Call it like this  `cd message \u0026\u0026 node encode_test.js @feedPubKey.ed25519` and re-run `go test`.\n\n```bash\n$ go test ./plugins/...\nok  \tgithub.com/ssbc/go-ssb/plugins/blobs\t0.021s\n?   \tgithub.com/ssbc/go-ssb/plugins/control\t[no test files]\nok  \tgithub.com/ssbc/go-ssb/plugins/gossip\t0.667s\n?   \tgithub.com/ssbc/go-ssb/plugins/test\t[no test files]\n?   \tgithub.com/ssbc/go-ssb/plugins/whoami\t[no test files]\n```\n\n(Sometimes the gossip test blocks indefinitely. This is a bug in go-muxrpcs closing behavior. See [the FAQ](./docs/faq.md) for more information.)\n\nTo run the interop tests you need to install the dependencies first and then run the tests. Diagnosing a failure might require adding the `-v` flag to get the stderr output from the nodejs process.\n\n```bash\n$ cd message/legacy \u0026\u0026 npm ci\n$ go test -v\n$ cd -\n$ cd tests \u0026\u0026 npm ci\n$ go test -v\n```\n\n## CI\n\nThe tests run under [this Github Actions configuration](./.github/workflows/go.yml).\n\nWe cache both the global `~/.npm` and `**/node_modules` to reduce build times.\nThis seems like a reasonable approach because we're testing against a single\nNode.js version and a locked package set. Go dependencies are also cached.\n\n## Stack links\n\n* [secret-handshake](https://secret-handshake.club) key exchange using [secretstream](https://godoc.org/github.com/ssbc/go-secretstream)\n* JS interoparability by using [go-muxprc](https://godoc.org/github.com/ssbc/go-muxrpc)\n* Embedded datastore, no external database required ([margaret](https://godoc.org/github.com/ssbc/margaret) abstraction with [BadgerDB](https://github.com/dgraph-io/badger) backend, similar to [flumedb](https://github.com/flumedb/flumedb))\n* [pull-stream](https://pull-stream.github.io)-like abstraction (called [luigi](https://godoc.org/github.com/ssbc/go-luigi)) to pipe between rpc and database.\n\n## Contact\n\n* Post to the `#go-ssb` / `#go-ssb-dev` channels on ssb\n* [Raise an issue](https://github.com/ssbc/go-ssb/issues)\n* Or mention us individually on ssb\n  * cryptix: `@p13zSAiOpguI9nsawkGijsnMfWmFd5rlUNpzekEE+vI=.ed25519`\n  * keks: `@YXkE3TikkY4GFMX3lzXUllRkNTbj5E+604AkaO1xbz8=.ed25519`\n  * decentral1se `@i8OXtTYaK0PrF002pd4vpXmrlg98As7ZMaHGKoXixdM=.ed25519`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fssbc%2Fgo-ssb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fssbc%2Fgo-ssb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fssbc%2Fgo-ssb/lists"}