diff --git a/Makefile b/Makefile index 11b105ee..6103284b 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,10 @@ lint: ## Run linter @go vet ./... +.PHONY: docs +docs: ## Generate swagger docs + @go install github.com/swaggo/swag/cmd/swag@latest + @swag init -o docs -d internal/server -g server.go -pd .PHONY: db-migrations db-migrations: ## Run the migrations for the database diff --git a/cmd/archivista/main.go b/cmd/archivista/main.go index d93e2b06..7ab1c7a1 100644 --- a/cmd/archivista/main.go +++ b/cmd/archivista/main.go @@ -1,4 +1,4 @@ -// Copyright 2022 The Archivista Contributors +// Copyright 2022-2024 The Archivista Contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -30,13 +30,8 @@ import ( "syscall" "time" - "entgo.io/contrib/entgql" - "github.com/99designs/gqlgen/graphql/handler" - "github.com/99designs/gqlgen/graphql/playground" nested "github.com/antonfisher/nested-logrus-formatter" "github.com/gorilla/handlers" - "github.com/gorilla/mux" - "github.com/in-toto/archivista" "github.com/in-toto/archivista/internal/config" "github.com/in-toto/archivista/internal/metadatastorage/sqlstore" "github.com/in-toto/archivista/internal/objectstorage/blobstore" @@ -108,22 +103,10 @@ func main() { logrus.Infof("executing phase 3: create and register http service (time since start: %s)", time.Since(startTime)) // ******************************************************************************** now = time.Now() - server := server.New(sqlStore, fileStore) - router := mux.NewRouter() - router.HandleFunc("/download/{gitoid}", server.GetHandler) - router.HandleFunc("/upload", server.StoreHandler) - - if cfg.EnableGraphql { - client := sqlStore.GetClient() - srv := handler.NewDefaultServer(archivista.NewSchema(client)) - srv.Use(entgql.Transactioner{TxOpener: client}) - router.Handle("/query", srv) - if cfg.GraphqlWebClientEnable { - router.Handle("/", - playground.Handler("Archivista", "/query"), - ) - } - } + + // initialize the server + sqlClient := sqlStore.GetClient() + server := server.New(sqlStore, fileStore, cfg, sqlClient) listenAddress := cfg.ListenOn listenAddress = strings.ToLower(strings.TrimSpace(listenAddress)) @@ -146,7 +129,7 @@ func main() { handlers.AllowedOrigins(cfg.CORSAllowOrigins), handlers.AllowedMethods([]string{"GET", "POST", "OPTIONS"}), handlers.AllowedHeaders([]string{"Accept", "Content-Type", "Content-Length", "Accept-Encoding", "X-CSRF-Token", "Authorization"}), - )(router)); err != nil { + )(server.Router())); err != nil { logrus.Fatalf("unable to start http server: %+v", err) } }() diff --git a/docs/docs.go b/docs/docs.go new file mode 100644 index 00000000..f33069cd --- /dev/null +++ b/docs/docs.go @@ -0,0 +1,230 @@ +// Package docs Code generated by swaggo/swag. DO NOT EDIT +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": { + "name": "Archivista Contributors", + "url": "https://github.com/in-toto/archivista/issues/new" + }, + "license": { + "url": "https://opensource.org/licenses/Apache-2" + }, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/donwload/{gitoid}": { + "post": { + "description": "download an attestation", + "produces": [ + "application/json" + ], + "summary": "Download", + "deprecated": true, + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dsse.Envelope" + } + } + } + } + }, + "/upload": { + "post": { + "description": "stores an attestation", + "produces": [ + "application/json" + ], + "summary": "Store", + "deprecated": true, + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.StoreResponse" + } + } + } + } + }, + "/v1/donwload/{gitoid}": { + "post": { + "description": "download an attestation", + "produces": [ + "application/json" + ], + "tags": [ + "attestation" + ], + "summary": "Download", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dsse.Envelope" + } + } + } + } + }, + "/v1/query": { + "post": { + "description": "GraphQL query", + "produces": [ + "application/json" + ], + "tags": [ + "graphql" + ], + "summary": "Query GraphQL", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/archivista.Resolver" + } + } + } + } + }, + "/v1/upload": { + "post": { + "description": "stores an attestation", + "produces": [ + "application/json" + ], + "tags": [ + "attestation" + ], + "summary": "Store", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.StoreResponse" + } + } + } + } + } + }, + "definitions": { + "api.StoreResponse": { + "type": "object", + "properties": { + "gitoid": { + "type": "string" + } + } + }, + "archivista.Resolver": { + "type": "object" + }, + "dsse.Envelope": { + "type": "object", + "properties": { + "payload": { + "type": "array", + "items": { + "type": "integer" + } + }, + "payloadType": { + "type": "string" + }, + "signatures": { + "type": "array", + "items": { + "$ref": "#/definitions/dsse.Signature" + } + } + } + }, + "dsse.Signature": { + "type": "object", + "properties": { + "certificate": { + "type": "array", + "items": { + "type": "integer" + } + }, + "intermediates": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + "keyid": { + "type": "string" + }, + "sig": { + "type": "array", + "items": { + "type": "integer" + } + }, + "timestamps": { + "type": "array", + "items": { + "$ref": "#/definitions/dsse.SignatureTimestamp" + } + } + } + }, + "dsse.SignatureTimestamp": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "integer" + } + }, + "type": { + "$ref": "#/definitions/dsse.SignatureTimestampType" + } + } + }, + "dsse.SignatureTimestampType": { + "type": "string", + "enum": [ + "tsp" + ], + "x-enum-varnames": [ + "TimestampRFC3161" + ] + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "v1", + Host: "", + BasePath: "", + Schemes: []string{}, + Title: "Archivista API", + Description: "Archivista API", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/docs/swagger.json b/docs/swagger.json new file mode 100644 index 00000000..8491c315 --- /dev/null +++ b/docs/swagger.json @@ -0,0 +1,204 @@ +{ + "swagger": "2.0", + "info": { + "description": "Archivista API", + "title": "Archivista API", + "contact": { + "name": "Archivista Contributors", + "url": "https://github.com/in-toto/archivista/issues/new" + }, + "license": { + "url": "https://opensource.org/licenses/Apache-2" + }, + "version": "v1" + }, + "paths": { + "/donwload/{gitoid}": { + "post": { + "description": "download an attestation", + "produces": [ + "application/json" + ], + "summary": "Download", + "deprecated": true, + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dsse.Envelope" + } + } + } + } + }, + "/upload": { + "post": { + "description": "stores an attestation", + "produces": [ + "application/json" + ], + "summary": "Store", + "deprecated": true, + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.StoreResponse" + } + } + } + } + }, + "/v1/donwload/{gitoid}": { + "post": { + "description": "download an attestation", + "produces": [ + "application/json" + ], + "tags": [ + "attestation" + ], + "summary": "Download", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dsse.Envelope" + } + } + } + } + }, + "/v1/query": { + "post": { + "description": "GraphQL query", + "produces": [ + "application/json" + ], + "tags": [ + "graphql" + ], + "summary": "Query GraphQL", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/archivista.Resolver" + } + } + } + } + }, + "/v1/upload": { + "post": { + "description": "stores an attestation", + "produces": [ + "application/json" + ], + "tags": [ + "attestation" + ], + "summary": "Store", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.StoreResponse" + } + } + } + } + } + }, + "definitions": { + "api.StoreResponse": { + "type": "object", + "properties": { + "gitoid": { + "type": "string" + } + } + }, + "archivista.Resolver": { + "type": "object" + }, + "dsse.Envelope": { + "type": "object", + "properties": { + "payload": { + "type": "array", + "items": { + "type": "integer" + } + }, + "payloadType": { + "type": "string" + }, + "signatures": { + "type": "array", + "items": { + "$ref": "#/definitions/dsse.Signature" + } + } + } + }, + "dsse.Signature": { + "type": "object", + "properties": { + "certificate": { + "type": "array", + "items": { + "type": "integer" + } + }, + "intermediates": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + "keyid": { + "type": "string" + }, + "sig": { + "type": "array", + "items": { + "type": "integer" + } + }, + "timestamps": { + "type": "array", + "items": { + "$ref": "#/definitions/dsse.SignatureTimestamp" + } + } + } + }, + "dsse.SignatureTimestamp": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "integer" + } + }, + "type": { + "$ref": "#/definitions/dsse.SignatureTimestampType" + } + } + }, + "dsse.SignatureTimestampType": { + "type": "string", + "enum": [ + "tsp" + ], + "x-enum-varnames": [ + "TimestampRFC3161" + ] + } + } +} diff --git a/docs/swagger.yaml b/docs/swagger.yaml new file mode 100644 index 00000000..8d100082 --- /dev/null +++ b/docs/swagger.yaml @@ -0,0 +1,133 @@ +definitions: + api.StoreResponse: + properties: + gitoid: + type: string + type: object + archivista.Resolver: + type: object + dsse.Envelope: + properties: + payload: + items: + type: integer + type: array + payloadType: + type: string + signatures: + items: + $ref: '#/definitions/dsse.Signature' + type: array + type: object + dsse.Signature: + properties: + certificate: + items: + type: integer + type: array + intermediates: + items: + items: + type: integer + type: array + type: array + keyid: + type: string + sig: + items: + type: integer + type: array + timestamps: + items: + $ref: '#/definitions/dsse.SignatureTimestamp' + type: array + type: object + dsse.SignatureTimestamp: + properties: + data: + items: + type: integer + type: array + type: + $ref: '#/definitions/dsse.SignatureTimestampType' + type: object + dsse.SignatureTimestampType: + enum: + - tsp + type: string + x-enum-varnames: + - TimestampRFC3161 +info: + contact: + name: Archivista Contributors + url: https://github.com/in-toto/archivista/issues/new + description: Archivista API + license: + url: https://opensource.org/licenses/Apache-2 + title: Archivista API + version: v1 +paths: + /donwload/{gitoid}: + post: + deprecated: true + description: download an attestation + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/dsse.Envelope' + summary: Download + /upload: + post: + deprecated: true + description: stores an attestation + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/api.StoreResponse' + summary: Store + /v1/donwload/{gitoid}: + post: + description: download an attestation + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/dsse.Envelope' + summary: Download + tags: + - attestation + /v1/query: + post: + description: GraphQL query + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/archivista.Resolver' + summary: Query GraphQL + tags: + - graphql + /v1/upload: + post: + description: stores an attestation + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/api.StoreResponse' + summary: Store + tags: + - attestation +swagger: "2.0" diff --git a/go.mod b/go.mod index 44c3ed29..5b818d4a 100644 --- a/go.mod +++ b/go.mod @@ -21,12 +21,15 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 + github.com/swaggo/http-swagger/v2 v2.0.2 + github.com/swaggo/swag v1.16.2 github.com/vektah/gqlparser/v2 v2.5.10 golang.org/x/sync v0.5.0 ) require ( ariga.io/atlas v0.14.1-0.20230918065911-83ad451a4935 // indirect + github.com/KyleBanks/depth v1.2.1 // indirect github.com/agext/levenshtein v1.2.1 // indirect github.com/agnivade/levenshtein v1.1.1 // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect @@ -37,6 +40,10 @@ require ( github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/inflect v0.19.0 // indirect + github.com/go-openapi/jsonpointer v0.20.2 // indirect + github.com/go-openapi/jsonreference v0.20.4 // indirect + github.com/go-openapi/spec v0.20.14 // indirect + github.com/go-openapi/swag v0.22.7 // indirect github.com/go-test/deep v1.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/go-cmp v0.5.9 // indirect @@ -46,10 +53,12 @@ require ( github.com/hashicorp/golang-lru/v2 v2.0.3 // indirect github.com/hashicorp/hcl/v2 v2.13.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.4 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/kylelemons/godebug v1.1.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect @@ -60,6 +69,7 @@ require ( github.com/rs/xid v1.5.0 // indirect github.com/sosodev/duration v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/swaggo/files/v2 v2.0.0 // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/zclconf/go-cty v1.12.1 // indirect @@ -69,12 +79,11 @@ require ( go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/crypto v0.17.0 // indirect golang.org/x/exp v0.0.0-20221230185412-738e83a70c30 // indirect - golang.org/x/mod v0.10.0 // indirect + golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.19.0 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/sys v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.9.3 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + golang.org/x/tools v0.16.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 144a669a..25f52f9b 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,8 @@ github.com/99designs/gqlgen v0.17.41 h1:C1/zYMhGVP5TWNCNpmZ9Mb6CqT1Vr5SHEWoTOEJ3 github.com/99designs/gqlgen v0.17.41/go.mod h1:GQ6SyMhwFbgHR0a8r2Wn8fYgEwPxxmndLFPhU63+cJE= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8= github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= @@ -55,6 +57,14 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4= github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= +github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= +github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= +github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= +github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= +github.com/go-openapi/spec v0.20.14 h1:7CBlRnw+mtjFGlPDRZmAMnq35cRzI91xj03HVyUi/Do= +github.com/go-openapi/spec v0.20.14/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw= +github.com/go-openapi/swag v0.22.7 h1:JWrc1uc/P9cSomxfnsFSVWoE1FW6bNbrVPmpQYpCcR8= +github.com/go-openapi/swag v0.22.7/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= @@ -104,6 +114,8 @@ github.com/in-toto/go-witness v0.2.0 h1:lxp3+Kc4Der2C1jV9ZePjSCEHUr2NsB4sImXI5sZ github.com/in-toto/go-witness v0.2.0/go.mod h1:Jr6ZlYoVfTS3hjUSmJ10J8qiHjpF1cfSE4NLAIJpbLw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= @@ -113,15 +125,14 @@ github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6K github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= @@ -141,7 +152,7 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY 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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -166,6 +177,12 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw= +github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM= +github.com/swaggo/http-swagger/v2 v2.0.2 h1:FKCdLsl+sFCx60KFsyM0rDarwiUSZ8DqbfSyIKC9OBg= +github.com/swaggo/http-swagger/v2 v2.0.2/go.mod h1:r7/GBkAWIfK6E/OLnE8fXnviHiDeAHmgIyooa4xm3AQ= +github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04= +github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E= github.com/vektah/gqlparser/v2 v2.5.10 h1:6zSM4azXC9u4Nxy5YmdmGu4uKamfwsdKTwp5zsEealU= github.com/vektah/gqlparser/v2 v2.5.10/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc= github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= @@ -192,8 +209,8 @@ golang.org/x/exp v0.0.0-20221230185412-738e83a70c30/go.mod h1:CxIveKay+FTh1D0yPZ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -214,8 +231,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= @@ -225,8 +242,8 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= -golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= +golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -249,7 +266,6 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/internal/server/server.go b/internal/server/server.go index 065c136a..40c01d5b 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -1,4 +1,4 @@ -// Copyright 2022 The Archivista Contributors +// Copyright 2022-2024 The Archivista Contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -24,15 +24,24 @@ import ( "net/http" "strings" + "entgo.io/contrib/entgql" + "github.com/99designs/gqlgen/graphql/handler" + "github.com/99designs/gqlgen/graphql/playground" "github.com/edwarnicke/gitoid" "github.com/gorilla/mux" + "github.com/in-toto/archivista" + _ "github.com/in-toto/archivista/docs" + "github.com/in-toto/archivista/ent" + "github.com/in-toto/archivista/internal/config" "github.com/in-toto/archivista/pkg/api" "github.com/sirupsen/logrus" + httpSwagger "github.com/swaggo/http-swagger/v2" ) type Server struct { metadataStore Storer objectStore StorerGetter + router *mux.Router } type Storer interface { @@ -48,10 +57,50 @@ type StorerGetter interface { Getter } -func New(metadataStore Storer, objectStore StorerGetter) *Server { - return &Server{metadataStore, objectStore} +func New(metadataStore Storer, objectStore StorerGetter, cfg *config.Config, sqlClient *ent.Client) Server { + r := mux.NewRouter() + s := &Server{metadataStore, objectStore, nil} + + // TODO: remove from future version (v0.5.0) endpoint with version + r.HandleFunc("/download/{gitoid}", s.GetHandler) + r.HandleFunc("/upload", s.StoreHandler) + if cfg.EnableGraphql { + r.Handle("/query", s.Query(sqlClient)) + r.Handle("/v1/query", s.Query(sqlClient)) + } + + r.HandleFunc("/v1/download/{gitoid}", s.GetHandler) + r.HandleFunc("/v1/upload", s.StoreHandler) + if cfg.GraphqlWebClientEnable { + r.Handle("/", + playground.Handler("Archivista", "/v1/query"), + ) + } + r.PathPrefix("/swagger/").Handler(httpSwagger.WrapHandler) + s.router = r + + return *s + +} + +// @title Archivista API +// @description Archivista API +// @version v1 +// @contact.name Archivista Contributors +// @contact.url https://github.com/in-toto/archivista/issues/new +// @license Apache 2 +// @license.url https://opensource.org/licenses/Apache-2 +// InitRoutes initializes the HTTP API routes for the server +func (s *Server) Router() *mux.Router { + return s.router } +// @Summary Store +// @Description stores an attestation +// @Produce json +// @Success 200 {object} api.StoreResponse +// @Tags attestation +// @Router /v1/upload [post] func (s *Server) Store(ctx context.Context, r io.Reader) (api.StoreResponse, error) { payload, err := io.ReadAll(r) if err != nil { @@ -79,6 +128,12 @@ func (s *Server) Store(ctx context.Context, r io.Reader) (api.StoreResponse, err return api.StoreResponse{Gitoid: gid.String()}, nil } +// @Summary Store +// @Description stores an attestation +// @Produce json +// @Success 200 {object} api.StoreResponse +// @Router /upload [post] +// @Deprecated func (s *Server) StoreHandler(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, fmt.Sprintf("%s is an unsupported method", r.Method), http.StatusBadRequest) @@ -102,6 +157,12 @@ func (s *Server) StoreHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") } +// @Summary Download +// @Description download an attestation +// @Produce json +// @Success 200 {object} dsse.Envelope +// @Tags attestation +// @Router /v1/donwload/{gitoid} [post] func (s *Server) Get(ctx context.Context, gitoid string) (io.ReadCloser, error) { if len(strings.TrimSpace(gitoid)) == 0 { return nil, errors.New("gitoid parameter is required") @@ -119,6 +180,12 @@ func (s *Server) Get(ctx context.Context, gitoid string) (io.ReadCloser, error) return objReader, err } +// @Summary Download +// @Description download an attestation +// @Produce json +// @Success 200 {object} dsse.Envelope +// @Deprecated +// @Router /donwload/{gitoid} [post] func (s *Server) GetHandler(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, fmt.Sprintf("%s is an unsupported method", r.Method), http.StatusBadRequest) @@ -141,3 +208,15 @@ func (s *Server) GetHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") } + +// @Summary Query GraphQL +// @Description GraphQL query +// @Produce json +// @Success 200 {object} archivista.Resolver +// @Tags graphql +// @Router /v1/query [post] +func (s *Server) Query(sqlclient *ent.Client) *handler.Server { + srv := handler.NewDefaultServer(archivista.NewSchema(sqlclient)) + srv.Use(entgql.Transactioner{TxOpener: sqlclient}) + return srv +}