diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..354eebd --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +.git +node_modules/ diff --git a/Makefile b/Makefile index f982b54..61c711b 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,14 @@ test: - go test -p ./... + HISHTORY_TEST=1 go test -p 1 ./... build: + go build -o web/landing/www/hishtory-offline clients/local/client.go + go build -o web/landing/www/hishtory-online clients/remote/client.go docker build -t gcr.io/dworken-k8s/hishtory-static -f web/caddy/Dockerfile . - # docker build -t gcr.io/dworken-k8s/hishtory-api -f deploy/api/Dockerfile . + docker build -t gcr.io/dworken-k8s/hishtory-api -f server/Dockerfile . deploy: build - docker push gcr.io/dworken-k8s/hishtory-static - # docker push gcr.io/dworken-k8s/hishtory-api - kubectl patch deployment hishtory-static -p "{\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"ts\":\"`date|sed -e 's/ /_/g'|sed -e 's/:/-/g'`\"}}}}}}" - # kubectl patch deployment cascara-keys -p "{\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"ts\":\"`date|sed -e 's/ /_/g'|sed -e 's/:/-/g'`\"}}}}}}" +# docker push gcr.io/dworken-k8s/hishtory-static + docker push gcr.io/dworken-k8s/hishtory-api +# kubectl patch deployment hishtory-static -p "{\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"ts\":\"`date|sed -e 's/ /_/g'|sed -e 's/:/-/g'`\"}}}}}}" + kubectl patch deployment hishtory-api -p "{\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"ts\":\"`date|sed -e 's/ /_/g'|sed -e 's/:/-/g'`\"}}}}}}" diff --git a/clients/local/client.go b/clients/local/client.go index 251788a..33d0378 100644 --- a/clients/local/client.go +++ b/clients/local/client.go @@ -28,6 +28,14 @@ func main() { shared.CheckFatalError(shared.Enable()) case "disable": shared.CheckFatalError(shared.Disable()) + case "status": + config, err := shared.GetConfig() + shared.CheckFatalError(err) + fmt.Print("Hishtory: Offline Mode\nEnabled: ") + fmt.Print(config.IsEnabled) + fmt.Print("\n") + case "update": + shared.CheckFatalError(shared.Update("https://hishtory.dev/hishtory-offline")) default: shared.CheckFatalError(fmt.Errorf("unknown command: %s", os.Args[1])) } @@ -43,7 +51,7 @@ func getServerHostname() string { func query(query string) { userSecret, err := shared.GetUserSecret() shared.CheckFatalError(err) - db, err := shared.OpenDB() + db, err := shared.OpenLocalSqliteDb() shared.CheckFatalError(err) data, err := shared.Search(db, userSecret, query, 25) shared.CheckFatalError(err) @@ -58,18 +66,20 @@ func saveHistoryEntry() { } entry, err := shared.BuildHistoryEntry(os.Args) shared.CheckFatalError(err) - err = shared.Persist(*entry) + db, err := shared.OpenLocalSqliteDb() + shared.CheckFatalError(err) + err = shared.Persist(db, *entry) shared.CheckFatalError(err) } func export() { userSecret, err := shared.GetUserSecret() shared.CheckFatalError(err) - db, err := shared.OpenDB() + db, err := shared.OpenLocalSqliteDb() shared.CheckFatalError(err) data, err := shared.Search(db, userSecret, "", 0) shared.CheckFatalError(err) for _, entry := range data { fmt.Println(entry) } -} \ No newline at end of file +} diff --git a/clients/local/client_test.go b/clients/local/client_test.go index 55b033e..737d87e 100644 --- a/clients/local/client_test.go +++ b/clients/local/client_test.go @@ -25,7 +25,9 @@ func RunInteractiveBashCommands(t *testing.T, script string) string { func TestIntegration(t *testing.T) { // Set up - defer shared.BackupAndRestore(t) + defer shared.BackupAndRestore(t)() + + // TODO(ddworken): Test status // Test install out := RunInteractiveBashCommands(t, ` @@ -84,4 +86,5 @@ func TestIntegration(t *testing.T) { } } } -// TODO(ddworken): Test export \ No newline at end of file + +// TODO(ddworken): Test export diff --git a/clients/remote/client.go b/clients/remote/client.go index 06cfa4b..b2c308a 100644 --- a/clients/remote/client.go +++ b/clients/remote/client.go @@ -32,6 +32,15 @@ func main() { shared.CheckFatalError(shared.Enable()) case "disable": shared.CheckFatalError(shared.Disable()) + case "status": + config, err := shared.GetConfig() + shared.CheckFatalError(err) + fmt.Print("Hishtory: Online Mode\nEnabled: ") + fmt.Print(config.IsEnabled) + fmt.Print("\nSecret Key: " + config.UserSecret + "\n") + fmt.Print("Remote Server: " + getServerHostname() + "\n") + case "update": + shared.CheckFatalError(shared.Update("https://hishtory.dev/hishtory-online")) default: shared.CheckFatalError(fmt.Errorf("unknown command: %s", os.Args[1])) } @@ -41,7 +50,7 @@ func getServerHostname() string { if server := os.Getenv("HISHTORY_SERVER"); server != "" { return server } - return "http://localhost:8080" + return "https://api.hishtory.dev" } func query(query string) { @@ -53,11 +62,11 @@ func query(query string) { func doQuery(query string) ([]*shared.HistoryEntry, error) { userSecret, err := shared.GetUserSecret() if err != nil { - return nil, err + return nil, err } req, err := http.NewRequest("GET", getServerHostname()+"/api/v1/search", nil) if err != nil { - return nil, err + return nil, err } q := req.URL.Query() @@ -69,12 +78,12 @@ func doQuery(query string) ([]*shared.HistoryEntry, error) { client := &http.Client{} resp, err := client.Do(req) if err != nil { - return nil, err + return nil, err } defer resp.Body.Close() resp_body, err := ioutil.ReadAll(resp.Body) if err != nil { - return nil, err + return nil, err } if resp.Status != "200 OK" { return nil, fmt.Errorf("search API returned invalid result. status=" + resp.Status) @@ -82,7 +91,7 @@ func doQuery(query string) ([]*shared.HistoryEntry, error) { var data []*shared.HistoryEntry err = json.Unmarshal(resp_body, &data) - return data, err + return data, err } func saveHistoryEntry() { @@ -111,5 +120,5 @@ func send(entry shared.HistoryEntry) error { } func export() { - -} \ No newline at end of file + // TODO(ddworken) +} diff --git a/clients/remote/client_test.go b/clients/remote/client_test.go index 0c83cd3..6cfde8f 100644 --- a/clients/remote/client_test.go +++ b/clients/remote/client_test.go @@ -12,7 +12,7 @@ import ( func RunInteractiveBashCommands(t *testing.T, script string) string { cmd := exec.Command("bash", "-i") - cmd.Stdin = strings.NewReader(script) + cmd.Stdin = strings.NewReader("export HISHTORY_SERVER=http://localhost:8080; /tmp/server &; sleep 2; " + script + "\nsleep 2; killall server || true;") var out bytes.Buffer cmd.Stdout = &out var err bytes.Buffer @@ -23,9 +23,11 @@ func RunInteractiveBashCommands(t *testing.T, script string) string { func TestIntegration(t *testing.T) { // Set up - defer shared.BackupAndRestore(t) + defer shared.BackupAndRestore(t)() - // Test init +// TODO(ddworken): Test status + + // Test install out := RunInteractiveBashCommands(t, ` gvm use go1.17 cd ../../ @@ -39,8 +41,7 @@ func TestIntegration(t *testing.T) { } // Test recording commands - out = RunInteractiveBashCommands(t, `/tmp/server & - sleep 2 # to give the server time to start + out = RunInteractiveBashCommands(t, ` ls /a ls /bar ls /foo @@ -51,12 +52,12 @@ func TestIntegration(t *testing.T) { hishtory enable echo thisisrecorded `) - if out != "Listening on localhost:8080\nfoo\nbar\nthisisnotrecorded\nthisisrecorded\n" { + if out != "foo\nbar\nthisisnotrecorded\nthisisrecorded\n" { t.Fatalf("unexpected output from running commands: %#v", out) } // Test querying for all commands - out = RunInteractiveBashCommands(t, `/tmp/server & hishtory query`) + out = RunInteractiveBashCommands(t, `hishtory query`) expected := []string{"echo thisisrecorded", "hishtory enable", "echo bar", "echo foo", "ls /foo", "ls /bar", "ls /a", "ms"} for _, item := range expected { if !strings.Contains(out, item) { @@ -85,4 +86,4 @@ func TestIntegration(t *testing.T) { } } -// TODO(ddworken): Test export \ No newline at end of file +// TODO(ddworken): Test export diff --git a/go.mod b/go.mod index 4b1aff8..f58dfff 100644 --- a/go.mod +++ b/go.mod @@ -5,16 +5,28 @@ go 1.17 require ( github.com/fatih/color v1.13.0 github.com/google/uuid v1.3.0 + github.com/lib/pq v1.10.2 github.com/rodaine/table v1.0.1 + gorm.io/driver/postgres v1.3.1 gorm.io/driver/sqlite v1.2.6 - gorm.io/gorm v1.22.4 + gorm.io/gorm v1.23.1 ) require ( + github.com/jackc/chunkreader/v2 v2.0.1 // indirect + github.com/jackc/pgconn v1.10.1 // indirect + github.com/jackc/pgio v1.0.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgproto3/v2 v2.2.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect + github.com/jackc/pgtype v1.9.1 // indirect + github.com/jackc/pgx/v4 v4.14.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect - github.com/jinzhu/now v1.1.3 // indirect + github.com/jinzhu/now v1.1.4 // indirect github.com/mattn/go-colorable v0.1.9 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-sqlite3 v1.14.9 // indirect + golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect + golang.org/x/text v0.3.7 // indirect ) diff --git a/go.sum b/go.sum index 6a8a925..c26bfec 100644 --- a/go.sum +++ b/go.sum @@ -1,17 +1,96 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= +github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= +github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= +github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= +github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= +github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= +github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= +github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.10.1 h1:DzdIHIjG1AxGwoEEqS+mGsURyjt4enSmqzACXvVzOT8= +github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= +github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= +github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= +github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.2.0 h1:r7JypeP2D3onoQTCxWdTpCtJ4D+qpKr0TxvoyMhZ5ns= +github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= +github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= +github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= +github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= +github.com/jackc/pgtype v1.9.1 h1:MJc2s0MFS8C3ok1wQTdQxWuXQcB6+HwAm5x1CzW7mf0= +github.com/jackc/pgtype v1.9.1/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= +github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= +github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= +github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= +github.com/jackc/pgx/v4 v4.14.1 h1:71oo1KAGI6mXhLiTMn6iDFcp3e7+zon/capWjl2OEFU= +github.com/jackc/pgx/v4 v4.14.1/go.mod h1:RgDuE4Z34o7XE92RpLsvFiOEfrAUT0Xt2KxvX73W06M= +github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.2.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jinzhu/now v1.1.3 h1:PlHq1bSCSZL9K0wUhbm2pGLoTWs2GwVhsP6emvGV/ZI= -github.com/jinzhu/now v1.1.3/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas= +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= +github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= @@ -19,23 +98,112 @@ github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/Qd github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rodaine/table v1.0.1 h1:U/VwCnUxlVYxw8+NJiLIuCxA/xa6jL38MY3FYysVWWQ= github.com/rodaine/table v1.0.1/go.mod h1:UVEtfBsflpeEcD56nF4F5AocNFta0ZuolpSVdPtlmP4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/postgres v1.3.1 h1:Pyv+gg1Gq1IgsLYytj/S2k7ebII3CzEdpqQkPOdH24g= +gorm.io/driver/postgres v1.3.1/go.mod h1:WwvWOuR9unCLpGWCL6Y3JOeBWvbKi6JLhayiVclSZZU= gorm.io/driver/sqlite v1.2.6 h1:SStaH/b+280M7C8vXeZLz/zo9cLQmIGwwj3cSj7p6l4= gorm.io/driver/sqlite v1.2.6/go.mod h1:gyoX0vHiiwi0g49tv+x2E7l8ksauLK0U/gShcdUsjWY= gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= -gorm.io/gorm v1.22.4 h1:8aPcyEJhY0MAt8aY6Dc524Pn+pO29K+ydu+e/cXSpQM= -gorm.io/gorm v1.22.4/go.mod h1:1aeVC+pe9ZmvKZban/gW4QPra7PRoTEssyc922qCAkk= +gorm.io/gorm v1.23.1 h1:aj5IlhDzEPsoIyOPtTRVI+SyaN1u6k613sbt4pwbxG0= +gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/hishtory b/hishtory new file mode 100755 index 0000000..a123e59 Binary files /dev/null and b/hishtory differ diff --git a/k8s/hishtory-api.yaml b/k8s/hishtory-api.yaml new file mode 100644 index 0000000..c5670c5 --- /dev/null +++ b/k8s/hishtory-api.yaml @@ -0,0 +1,47 @@ +apiVersion: v1 +kind: Service +metadata: + name: hishtory-api +spec: + ports: + - port: 80 + targetPort: 8080 + selector: + app: hishtory-api +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: hishtory-api +spec: + revisionHistoryLimit: 5 + selector: + matchLabels: + app: hishtory-api + replicas: 1 + template: + metadata: + labels: + app: hishtory-api + spec: + containers: + - name: hishtory-api + image: gcr.io/dworken-k8s/hishtory-api + imagePullPolicy: Always + ports: + - containerPort: 80 + volumeMounts: + - name: aws-secret-volume + mountPath: /root/awscreds/ + env: + - name: AWS_SHARED_CREDENTIALS_FILE + value: /root/.aws/credentials + - name: DOGSTATSD_HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + + volumes: + - name: aws-secret-volume + secret: + secretName: aws-secret diff --git a/server/Dockerfile b/server/Dockerfile new file mode 100644 index 0000000..8162ad3 --- /dev/null +++ b/server/Dockerfile @@ -0,0 +1,8 @@ +FROM golang:1.17 +COPY go.mod ./ +COPY go.sum ./ +RUN unset GOPATH; go mod download +COPY . ./ +RUN unset GOPATH; go build -o /server server/server.go +CMD [ "/server" ] + diff --git a/server/server.go b/server/server.go index b7de13a..8fe47f3 100644 --- a/server/server.go +++ b/server/server.go @@ -8,6 +8,13 @@ import ( "strconv" "github.com/ddworken/hishtory/shared" + _ "github.com/lib/pq" + "gorm.io/driver/postgres" + "gorm.io/gorm" +) + +const ( + POSTGRES_DB = "postgresql://postgres:O74Ji4735C@postgres-postgresql.default.svc.cluster.local:5432/hishtory?sslmode=disable" ) func apiSubmitHandler(w http.ResponseWriter, r *http.Request) { @@ -17,10 +24,27 @@ func apiSubmitHandler(w http.ResponseWriter, r *http.Request) { if err != nil { panic(err) } - err = shared.Persist(entry) + db, err := OpenDB() if err != nil { panic(err) } + err = shared.Persist(db, entry) + if err != nil { + panic(err) + } +} + +func OpenDB() (*gorm.DB, error) { + if shared.IsTestEnvironment() { + return shared.OpenLocalSqliteDb() + } + + db, err := gorm.Open(postgres.Open(POSTGRES_DB), &gorm.Config{}) + if err != nil { + return nil, fmt.Errorf("failed to connect to the DB: %v", err) + } + db.AutoMigrate(&shared.HistoryEntry{}) + return db, nil } func apiSearchHandler(w http.ResponseWriter, r *http.Request) { @@ -32,7 +56,7 @@ func apiSearchHandler(w http.ResponseWriter, r *http.Request) { if err != nil { limit = 0 } - db, err := shared.OpenDB() + db, err := OpenDB() if err != nil { panic(err) } @@ -51,7 +75,18 @@ func apiSearchHandler(w http.ResponseWriter, r *http.Request) { } func main() { - _, err := shared.OpenDB() + // db, err := sql.Open("postgres", "postgresql://postgres:O74Ji4735C@postgres-postgresql.default.svc.cluster.local:5432/cascara_prod?sslmode=disable") + // if err != nil { + // panic(err) + // } + // defer db.Close() + + // _, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s;", "hishtory")) + // if err != nil { + // panic(err) + // } + + _, err := OpenDB() if err != nil { panic(err) } diff --git a/server/server_test.go b/server/server_test.go index 2ef0ea4..06ac203 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -13,7 +13,7 @@ import ( func TestSubmitThenQuery(t *testing.T) { // Set up - defer shared.BackupAndRestore(t) + defer shared.BackupAndRestore(t)() shared.Check(t, shared.Setup([]string{})) // Submit an entry @@ -59,7 +59,7 @@ func TestSubmitThenQuery(t *testing.T) { func TestNoUserSecretGivesNoResults(t *testing.T) { // Set up - defer shared.BackupAndRestore(t) + defer shared.BackupAndRestore(t)() shared.Check(t, shared.Setup([]string{})) // Submit an entry @@ -87,7 +87,7 @@ func TestNoUserSecretGivesNoResults(t *testing.T) { func TestSearchQuery(t *testing.T) { // Set up - defer shared.BackupAndRestore(t) + defer shared.BackupAndRestore(t)() shared.Check(t, shared.Setup([]string{})) // Submit an entry that we'll match diff --git a/shared/client.go b/shared/client.go index 7c62144..c5e2706 100644 --- a/shared/client.go +++ b/shared/client.go @@ -3,6 +3,7 @@ package shared import ( _ "embed" + "bytes" "encoding/json" "fmt" "io" @@ -40,6 +41,9 @@ func getCwd() (string, error) { if err != nil { return "", fmt.Errorf("failed to get user's home directory: %v", err) } + if cwd == homedir { + return "~/", nil + } if strings.HasPrefix(cwd, homedir) { return strings.Replace(cwd, homedir, "~", 1), nil } @@ -242,6 +246,12 @@ func Install() error { } func configureBashrc(homedir, binaryPath string) error { + // Create the file we're going to source in our bashrc. Do this no matter what in case there are updates to it. + bashConfigPath := path.Join(filepath.Dir(binaryPath), "config.sh") + err := ioutil.WriteFile(bashConfigPath, []byte(CONFIG_SH_CONTENTS), 0644) + if err != nil { + return fmt.Errorf("failed to write config.sh file: %v", err) + } // Check if we need to configure the bashrc bashrc, err := ioutil.ReadFile(path.Join(homedir, ".bashrc")) if err != nil { @@ -250,13 +260,6 @@ func configureBashrc(homedir, binaryPath string) error { if strings.Contains(string(bashrc), "# Hishtory Config:") { return nil } - // Create the file we're going to source in our bashrc - bashConfigPath := path.Join(filepath.Dir(binaryPath), "config.sh") - err = ioutil.WriteFile(bashConfigPath, []byte(CONFIG_SH_CONTENTS), 0644) - if err != nil { - return fmt.Errorf("failed to write config.sh file: %v", err) - } - // Add to bashrc f, err := os.OpenFile(path.Join(homedir, ".bashrc"), os.O_APPEND|os.O_WRONLY, 0644) if err != nil { @@ -272,15 +275,14 @@ func configureBashrc(homedir, binaryPath string) error { func installBinary(homedir string) (string, error) { clientPath, err := exec.LookPath("hishtory") - if err == nil { - return clientPath, nil - } - clientDir := path.Join(homedir, ".hishtory-bin") - err = os.MkdirAll(clientDir, 0744) if err != nil { - return "", fmt.Errorf("failed to create folder for hishtory binary: %v", err) + clientDir := path.Join(homedir, ".hishtory-bin") + err = os.MkdirAll(clientDir, 0744) + if err != nil { + return "", fmt.Errorf("failed to create folder for hishtory binary: %v", err) + } + clientPath = path.Join(clientDir, "hishtory") } - clientPath = path.Join(clientDir, "hishtory") err = copyFile(os.Args[0], clientPath) if err != nil { return "", fmt.Errorf("failed to copy hishtory binary to $PATH: %v", err) @@ -316,3 +318,16 @@ func copyFile(src, dst string) error { _, err = io.Copy(destination, source) return err } + +func Update(url string) error { + var stdout bytes.Buffer + var stderr bytes.Buffer + cmd := exec.Command("bash", "-c", "curl -o /tmp/hishtory-client "+url+"; chmod +x /tmp/hishtory-client; /tmp/hishtory-client install") + cmd.Stdout = &stdout + cmd.Stderr = &stderr + err := cmd.Run() + if err != nil { + return fmt.Errorf("Failed to update: %v, stdout=%+v, stderr=%+v", err, stdout.String(), stderr.String()) + } + return nil +} diff --git a/shared/config.sh b/shared/config.sh index 92eabd8..7c3fa30 100644 --- a/shared/config.sh +++ b/shared/config.sh @@ -22,6 +22,6 @@ function PostCommand() { fi # Run after every prompt - hishtory saveHistoryEntry $? "`history 1`" $HISHTORY_START_TIME + (hishtory saveHistoryEntry $? "`history 1`" $HISHTORY_START_TIME &) } PROMPT_COMMAND="PostCommand" diff --git a/shared/data.go b/shared/data.go index 3c855b0..ae557b7 100644 --- a/shared/data.go +++ b/shared/data.go @@ -2,13 +2,13 @@ package shared import ( "fmt" - "os" - "path" "strings" "time" + "os" +"path" - "gorm.io/driver/sqlite" "gorm.io/gorm" + "gorm.io/driver/sqlite" ) type HistoryEntry struct { @@ -26,18 +26,11 @@ const ( DB_PATH = ".hishtory.db" ) -func Persist(entry HistoryEntry) error { - db, err := OpenDB() - if err != nil { - return err - } - conn, err := db.DB() - defer conn.Close() - db.Create(&entry).Commit() - return nil +func IsTestEnvironment() bool { + return os.Getenv("HISHTORY_TEST") != "" } -func OpenDB() (*gorm.DB, error) { +func OpenLocalSqliteDb() (*gorm.DB, error) { homedir, err := os.UserHomeDir() if err != nil { return nil, fmt.Errorf("failed to get user's home directory: %v", err) @@ -50,6 +43,12 @@ func OpenDB() (*gorm.DB, error) { return db, nil } + +func Persist(db *gorm.DB, entry HistoryEntry) error { + db.Create(&entry).Commit() + return nil +} + func Search(db *gorm.DB, userSecret, query string, limit int) ([]*HistoryEntry, error) { tokens, err := tokenize(query) if err != nil { diff --git a/shared/data_test.go b/shared/data_test.go index f4d8ddd..86e8ff6 100644 --- a/shared/data_test.go +++ b/shared/data_test.go @@ -7,12 +7,12 @@ import ( func TestPersist(t *testing.T) { defer BackupAndRestore(t) Check(t, Setup([]string{})) + db, err := OpenLocalSqliteDb() + Check(t, err) + entry, err := BuildHistoryEntry([]string{"unused", "saveHistoryEntry", "120", " 123 ls / ", "1641774958326745663"}) Check(t, err) - Check(t, Persist(*entry)) - - db, err := OpenDB() - Check(t, err) + Check(t, Persist(db, *entry)) var historyEntries []*HistoryEntry result := db.Find(&historyEntries) Check(t, result.Error) @@ -28,21 +28,21 @@ func TestPersist(t *testing.T) { func TestSearch(t *testing.T) { defer BackupAndRestore(t) Check(t, Setup([]string{})) + db, err := OpenLocalSqliteDb() + Check(t, err) // Insert data entry1, err := BuildHistoryEntry([]string{"unused", "saveHistoryEntry", "120", " 123 ls / ", "1641774958326745663"}) Check(t, err) - Check(t, Persist(*entry1)) + Check(t, Persist(db, *entry1)) entry2, err := BuildHistoryEntry([]string{"unused", "saveHistoryEntry", "120", " 123 ls /foo ", "1641774958326745663"}) Check(t, err) - Check(t, Persist(*entry2)) + Check(t, Persist(db, *entry2)) entry3, err := BuildHistoryEntry([]string{"unused", "saveHistoryEntry", "120", " 123 echo hi ", "1641774958326745663"}) Check(t, err) - Check(t, Persist(*entry3)) + Check(t, Persist(db, *entry3)) // Search for data - db, err := OpenDB() - Check(t, err) secret, err := GetUserSecret() Check(t, err) results, err := Search(db, secret, "ls", 5) diff --git a/web/landing/www/demo.png b/web/landing/www/demo.png new file mode 100644 index 0000000..a5a4160 Binary files /dev/null and b/web/landing/www/demo.png differ diff --git a/web/landing/www/hishtory-offline b/web/landing/www/hishtory-offline new file mode 100755 index 0000000..f9aaa81 Binary files /dev/null and b/web/landing/www/hishtory-offline differ diff --git a/web/landing/www/hishtory-online b/web/landing/www/hishtory-online new file mode 100755 index 0000000..0785b57 Binary files /dev/null and b/web/landing/www/hishtory-online differ diff --git a/web/landing/www/index.html b/web/landing/www/index.html index b85d5b8..f725dcc 100644 --- a/web/landing/www/index.html +++ b/web/landing/www/index.html @@ -23,27 +23,6 @@ gtag('config', 'UA-144207374-1'); - - - - @@ -82,13 +61,10 @@ About - @@ -99,15 +75,12 @@
-
-

Low Friction Security for Startups

+
+

Your shell history: synced, queryable, and in context


-

- Cascara SSH eliminates the need to manage SSH keys and increases security. -

- Find Out More +
@@ -118,30 +91,15 @@
-

SSH security integrated with GSuite

+

Bash scripting is powerful, keep track of how you use it


- Rely on Google's security for authenticating users and enforcing 2FA. Cascara builds on top of - Google - in order to seamlessly provision short lived SSH keys. Deploy one key to all of your servers and use - SSH the same way everyone from Facebook to Uber does. -

- According to ssh.com, 90% of SSH - keys in a typical enterprise company are not actively used. Cascara ensures - that no inactive keys exist thereby reducing the threat of a breach. + Bash keeps a list of every command you run locally, but this list of commands is devoid of context (where did I run that command? what was the output of the command? how long did it take to run?) and it is easily corrupted (open two terminals at once? Say goodbye to your bash history!). +
+
+ Hishtory keeps track of the command you ran, how long it took to run, whether it succeeded or failed, where you ran it, and on what machine. It syncs this information across all your machines, so you can always find that useful bash pipeline you wrote a month ago.

-

-

-              
-david@laptop $ cssh david@cascarasecurity.com
-Logging in with Google...       # Opens a browser window to login using OAuth
-Provisioning a new SSH key...
-Session Established
-david@cascarasecurity.com $
-              
-            

@@ -152,54 +110,13 @@ david@cascarasecurity.com $

Setup Process


-
-
-
- -

Signup

-

Configure custom SSH permissions through our website

-
-
-
-
- -

Deploy

-

Deploy a single SSH certificate on all of your servers

-
-
-
-
- -

Install

-

Install the open source cssh binary on your computer

-
-
-
-
- -

Work, securely

-

Get back to the things that matter, confident that your servers are - secure

-
-
-
-
- - - -
-
-
-
-

Sign up

-

- Sign up now and get started within 10 minutes -

-
- Get - Started! -
-
+

+ To install hishtory in offline mode: `curl -o hishtory https://hishtory.dev/hishtory-offline; chmod +x hishtory; ./hishtory install` +
+ To install hishtory in online mode on your first machine: `curl -o hishtory https://hishtory.dev/hishtory-online; chmod +x hishtory; ./hishtory install` +
+ To install hishtory in online mode on your other machines: `curl -o hishtory https://hishtory.dev/hishtory-online; chmod +x hishtory; ./hishtory install $YOUR_HISHTORY_SECRET` +

@@ -225,10 +142,11 @@ david@cascarasecurity.com $
- SSH has a concept of "certificate authorities" where a single master key is placed on - the server, and that key is used to create temporary keys that automatically expire - after a set period of time. Cascara automates this process of provisioning new temporary - keys based off of authenticating with your Google account. + Hishtory hooks into your shell to record everything you could want to know about your shell history. It supports two modes: +
    +
  1. Offline mode: It persists all this data in a local SQLite database
  2. +
  3. Online mode: Only if you opt-in, it syncs this data between all your machines so your history is immediately queryable from every one of your machines
  4. +
@@ -237,7 +155,7 @@ david@cascarasecurity.com $

@@ -245,14 +163,7 @@ david@cascarasecurity.com $
- Security is never absolute, but we believe that this does raise the bar for security. - Cascara centralizes your SSH security so that one must attack Google in order to - attack your SSH servers. -

- Using this service also requires trusting us. We maintain a warrant - canary that we promise to keep up to date. In order to ensure that compromising us - does not allow an attacker to compromise your servers, we recommend either configuring - 2FA or a bastion host following the guides in the admin console. + Yes! The default is to use it in the offline mode where your shell history stays 100% local and never leaves your machine. Only if you opt-in will it be synced to your other machines with hishtory installed.
@@ -262,22 +173,14 @@ david@cascarasecurity.com $
- Cascara eliminates the need to onboard and offboard engineers by manually editing the - SSH keys deployed on servers. - Even if you use Ansible or Chef to manage SSH keys, Cascara ensures that you do not need - to wait for every server to get updated. With Cascara, you simply add or remove - someone's - email and it is done. -

- Cascara also removes the time consuming process of rotating SSH keys since all keys - automatically expire. + If it works for you, great! But I find I constantly get annoyed with `.bash_history` either because I lose context (which directory do I need to run that command from?) or because I full on lose the file (it tends to get corrupted if you open multiple terminals at the same time).
@@ -287,16 +190,14 @@ david@cascarasecurity.com $
- Nothing! We are dedicated to ensuring that hobbyists and small startups can use our - product. Overtime we plan on - adding more enterprise focused features which we will charge for. + Yes! This is just a hobby project for me that I use, and I hope other people get some use out of.
@@ -315,12 +216,7 @@ david@cascarasecurity.com $ Made with ❤️ by David Dworken. - I'm a Security Engineer with experience working - everywhere from Snapchat to Keybase. I designed Cascara to solve a recurring - security problem I've seen time and time again. In addition, it has been designed - from the ground up with a secure scalable architecture. -

- More features are incoming! + I'm a Security Engineer working at Google. I built this to solve a problem for myself, and wanted to share it with others who may find it useful. @@ -334,7 +230,7 @@ david@cascarasecurity.com $
@@ -343,7 +239,7 @@ david@cascarasecurity.com $