Make use of CORS, add more tests

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
This commit is contained in:
Gabriel Adrian Samfira 2022-07-05 19:28:50 +00:00
parent 87c77f6966
commit 535f39a1ba
9 changed files with 310 additions and 5 deletions

View file

@ -32,6 +32,8 @@ import (
"garm/runner"
"garm/util"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/pkg/errors"
)
@ -117,6 +119,12 @@ func main() {
}
router := routers.NewAPIRouter(controller, logWriter, jwtMiddleware, initMiddleware, instanceMiddleware)
corsMw := mux.CORSMethodMiddleware(router)
router.Use(corsMw)
allowedOrigins := handlers.AllowedOrigins(cfg.APIServer.CORSOrigins)
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS", "DELETE"})
headersOk := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type", "Authorization"})
tlsCfg, err := cfg.APIServer.APITLSConfig()
if err != nil {
@ -127,7 +135,7 @@ func main() {
Addr: cfg.APIServer.BindAddress(),
TLSConfig: tlsCfg,
// Pass our instance of gorilla/mux in.
Handler: router,
Handler: handlers.CORS(methodsOk, headersOk, allowedOrigins)(router),
}
listener, err := net.Listen("tcp", srv.Addr)

View file

@ -141,10 +141,19 @@ func (c *Config) Validate() error {
return errors.Wrap(err, "validating jwt config")
}
providerNames := map[string]int{}
for _, provider := range c.Providers {
if err := provider.Validate(); err != nil {
return errors.Wrap(err, "validating provider")
}
providerNames[provider.Name] += 1
}
for name, count := range providerNames {
if count > 1 {
return fmt.Errorf("duplicate provider name %s", name)
}
}
return nil
@ -165,10 +174,12 @@ func (d *Default) Validate() error {
return fmt.Errorf("missing callback_url")
}
if d.ConfigDir != "" {
if _, err := os.Stat(d.ConfigDir); err != nil {
return errors.Wrap(err, "accessing config dir")
}
if d.ConfigDir == "" {
return fmt.Errorf("config_dir cannot be empty")
}
if _, err := os.Stat(d.ConfigDir); err != nil {
return errors.Wrap(err, "accessing config dir")
}
return nil

View file

@ -1 +1,175 @@
// Copyright 2022 Cloudbase Solutions SRL
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package config
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
var (
EncryptionPassphrase = "bocyasicgatEtenOubwonIbsudNutDom"
)
func getDefaultSectionConfig(configDir string) Default {
return Default{
ConfigDir: configDir,
CallbackURL: "https://garm.example.com/",
LogFile: filepath.Join(configDir, "garm.log"),
}
}
func getDefaultTLSConfig() TLSConfig {
return TLSConfig{
CRT: "../testdata/certs/srv-pub.pem",
Key: "../testdata/certs/srv-key.pem",
CACert: "../testdata/certs/ca-pub.pem",
}
}
func getDefaultAPIServerConfig() APIServer {
return APIServer{
Bind: "0.0.0.0",
Port: 9998,
UseTLS: true,
TLSConfig: getDefaultTLSConfig(),
CORSOrigins: []string{},
}
}
func getDefaultDatabaseConfig(dir string) Database {
return Database{
Debug: false,
DbBackend: SQLiteBackend,
SQLite: SQLite{
DBFile: filepath.Join(dir, "garm.db"),
},
Passphrase: EncryptionPassphrase,
}
}
func getDefaultProvidersConfig() []Provider {
lxdConfig := getDefaultLXDConfig()
return []Provider{
{
Name: "test_lxd",
ProviderType: LXDProvider,
Description: "test LXD provider",
LXD: lxdConfig,
},
}
}
func getDefaultGithubConfig() []Github {
return []Github{
{
Name: "dummy_creds",
Description: "dummy github credentials",
OAuth2Token: "bogus",
},
}
}
func getDefaultJWTCofig() JWTAuth {
return JWTAuth{
Secret: EncryptionPassphrase,
TimeToLive: "48h",
}
}
func getDefaultConfig(t *testing.T) Config {
dir, err := ioutil.TempDir("", "garm-config-test")
if err != nil {
t.Fatalf("failed to create temporary directory: %s", err)
}
t.Cleanup(func() { os.RemoveAll(dir) })
return Config{
Default: getDefaultSectionConfig(dir),
APIServer: getDefaultAPIServerConfig(),
Database: getDefaultDatabaseConfig(dir),
Providers: getDefaultProvidersConfig(),
Github: getDefaultGithubConfig(),
JWTAuth: getDefaultJWTCofig(),
}
}
func TestConfig(t *testing.T) {
cfg := getDefaultConfig(t)
err := cfg.Validate()
assert.Nil(t, err)
}
func TestDefaultSectionConfig(t *testing.T) {
dir, err := ioutil.TempDir("", "garm-config-test")
if err != nil {
t.Fatalf("failed to create temporary directory: %s", err)
}
t.Cleanup(func() { os.RemoveAll(dir) })
cfg := getDefaultSectionConfig(dir)
tests := []struct {
name string
cfg Default
errString string
}{
{
name: "Config is valid",
cfg: cfg,
errString: "",
},
{
name: "CallbackURL cannot be empty",
cfg: Default{
CallbackURL: "",
ConfigDir: cfg.ConfigDir,
},
errString: "missing callback_url",
},
{
name: "ConfigDir cannot be empty",
cfg: Default{
CallbackURL: cfg.CallbackURL,
ConfigDir: "",
},
errString: "config_dir cannot be empty",
},
{
name: "config_dir must exist and be accessible",
cfg: Default{
CallbackURL: cfg.CallbackURL,
ConfigDir: "/i/do/not/exist",
},
errString: "accessing config dir: stat /i/do/not/exist:.*",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
err := tc.cfg.Validate()
if tc.errString == "" {
assert.Nil(t, err)
} else {
assert.NotNil(t, err)
assert.Regexp(t, tc.errString, err.Error())
}
})
}
}

View file

@ -1,3 +1,17 @@
// Copyright 2022 Cloudbase Solutions SRL
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package config
import (

View file

@ -1,3 +1,17 @@
// Copyright 2022 Cloudbase Solutions SRL
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package config
import (

View file

@ -1,3 +1,17 @@
// Copyright 2022 Cloudbase Solutions SRL
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package config
import (

20
testdata/certs/ca-pub.pem vendored Normal file
View file

@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDTDCCAjSgAwIBAgIRAMrfG/ZCst3T0RtRgcnY5h0wDQYJKoZIhvcNAQELBQAw
MDEcMBoGA1UEChMTQ2xvdWRiYXNlIFNvbHV0aW9uczEQMA4GA1UEAxMHUm9vdCBD
QTAeFw0yMjA3MDQxODM3MjdaFw0zMjA3MDExODM3MjdaMDAxHDAaBgNVBAoTE0Ns
b3VkYmFzZSBTb2x1dGlvbnMxEDAOBgNVBAMTB1Jvb3QgQ0EwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCooxNCaSfs8UhVmavARonC5S2mFLCSLXrHGPhS
+hjAgqQrF8pI/LvJmsV1LAjYjIAqwE9eDIbuyj8nBuaPJYFoS4McaKZmuo/UYqgx
5K+rDfMdDUFIP0XGTopJFcfKguQQU6Tx+8v5Ubc8C9WjRFDRbmR5ihNzKb1Eb/y1
OrwmsNtMmgyZFCm6yDMymXFgqTo58zTj9d04uwumVLjSoJxPEqytf9LpKJoeoj7O
tnSq8OMPyhsPu3LgZyvyB65ehb1NChica99Dh5bee4muQAkYGUqbRXgbau6edhsQ
MtXM4mzaXdQIMva3rPfnBfPuhc9WjnKmmmOsWDv510nbl0hVAgMBAAGjYTBfMA4G
A1UdDwEB/wQEAwICBDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwDwYD
VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoesgOFlL4kKwT1enjyGkxCEUPSowDQYJ
KoZIhvcNAQELBQADggEBAHlWX8iDkTtADKMAbfBMzvsolzQjZALMab2Jdco7QKtO
i3g6k7UWsgAO+cbH8XCM87ty6JuPUFJNibLWHl1A4dSqwbGGNw+wLVLqNzu8dDqC
E1WG3rIFkXFa3z3eZhauBcdp2FCLbuHtD4g/yGHE/LExnIZeHMpbF2MuC0V34PhY
daj2FUYJe+hmiKRajXGYjv6jOTAbylLK8qzF7HmTnLIJ0hahmKnykC2FiwAVpxZC
T0OcNEXjR1FJfSVHJC2OCOZXPftP7ssZmO18j35UMGk/oxkrUz0839rQtT5oZPI6
UuNSyP3+BcQtdrDUiCOum651ojwvEO4umlQX3zGmo7U=
-----END CERTIFICATE-----

27
testdata/certs/srv-key.pem vendored Normal file
View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAyUksz2y+noPUEebojEhMmMUWV9Co+wEWx7QUnWuT9ywaU+Jl
4hucM8W+2kgLz4eo0Ih9TOgMasSeCXFQCYdHA6AHzUmzO54i3kuliRFP5QXnOoPS
Z5t8GrcnuX3eZ/VAlgdMygs74R1fBn3vCNIY9PVdoaR7dd66Nx1U13ayHG3Z9LnM
FMa0T2snnjONv3iL2ctZIlOKbYgOvKa9yjyGdSne20RJG659dpF8/0ovz6BmaRVl
5sE1sfF9Y84WXkZjDAvfg8rtTXSwSsuZeRlPz+wEP3tKtzCjzcUr61bd7M456pwD
9Y19dRsGEqP4A5tZ/xTeHol604n9STcKdxfVfwIDAQABAoIBAQC+SACmbcSdkT3v
VnxL8SUH3njKtySndFYWn7RFRKdyKC0TU5jA8RzvDGbpbuZLX5FE4WKiS1NBs3E6
t/XTrCCD2srFVICtQUbxIk3wj38ZoEUA2hEThLcDglV5UvXnDL/rlCcRcSFAJEXq
my5XBlY1a6cB4b4cpVsgMwg7T6f8mmcQv7Y5CjIH3P8RSjAQpoDRPCcDnEWieDnV
NDTPFKvOdXe01XMJ7YJ9jd3RE4exra3xeDJgB0EPxexlDpcLMxDEt3JfEbzr3xdc
sSXQbVzriYRv8jYV0xAond6itVDfoH6qGVGP+YiSKLeHbcML8WjeFtUhG8gYl/OX
RkrHzVGRAoGBAOYbyN6cb7EWDyr6V+s8o/lD67Zs1SCoa7mMxjbTsjuGuEjNsoLU
CetAUCbay7NZl37fwm7QE5PbOjr1ED6tgSi3Za9M/3GITFIrqRVbfIP5nyfJgbUQ
QLBZ9sb22rrWz5IWFx0jxWQzO6g3ZEPgRt47OO9xBmfJr77A+FRzNnEFAoGBAN/v
KQu2xBIdq4aiai/EepHG0YLToMVCgx0CZiajdl9QhJW4oBBYnYDm/elZSdksDmjy
8J80yUeZBQIkL6o2qIBrkrrcPl019KUtljiTDNQQhQqRqmN/HZxZXFXDVoMLvdJf
LQejtmT93pD4SsrQ8T5fV8qDjybSSKtw5A1zMMOzAoGAJZN389I78wEVLQGAhet7
I2NSBJI1I4YdQUmZvK5JNqtDQLBGbFLP49i2vgGQrhL9SDyl9Y6JA+YS1jnak0Gm
C84XDs9WD2YggHKcw94SsUJ8GPUw9y5WQfYO9GKvST922fY9hAapXzl2jnutJeBj
8jpdi8w7LYuj5VSBuNivlTkCgYAibAbpMAzvo/Pr3CdqdE9K/T7TV2iNKe4xlV7S
baoSeLQIt7qTCKwdVmSNbBY39de5Ni7aqiiOgu0MKTfSeFhqdR627of/l/2lLl67
D4+XQXrR5xZD+RQ6JlpVLJOtzS4+mja3x+iPmZ6Otjv49SlAJzO9g3+LviNBhzbn
Al/qlQKBgQCOx15o+udsT2LlVOUL6Gt6TBoin6BmepGK4plFPVs83pM2Ce7oYhr/
MBpgYO/CiYzFkWJdY91IHRswt8MYqIxpBZNv1TZntHlHVItEzgidSU8BkxMte8u4
iAvNm8KCSwFVopwcXaGOxtqUAgX7rJo9+y22KBMtYBAq1RWDI5DlOg==
-----END RSA PRIVATE KEY-----

23
testdata/certs/srv-pub.pem vendored Normal file
View file

@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIID1DCCArygAwIBAgIRAMlzfk77HwnF4vq4FSp5cvEwDQYJKoZIhvcNAQELBQAw
MDEcMBoGA1UEChMTQ2xvdWRiYXNlIFNvbHV0aW9uczEQMA4GA1UEAxMHUm9vdCBD
QTAeFw0yMjA3MDQxODM3MjdaFw0zMjA3MDExODM3MjdaMDMxHDAaBgNVBAoTE0Ns
b3VkYmFzZSBTb2x1dGlvbnMxEzARBgNVBAMTCnJlcGxpY2F0b3IwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJSSzPbL6eg9QR5uiMSEyYxRZX0Kj7ARbH
tBSda5P3LBpT4mXiG5wzxb7aSAvPh6jQiH1M6AxqxJ4JcVAJh0cDoAfNSbM7niLe
S6WJEU/lBec6g9Jnm3watye5fd5n9UCWB0zKCzvhHV8Gfe8I0hj09V2hpHt13ro3
HVTXdrIcbdn0ucwUxrRPayeeM42/eIvZy1kiU4ptiA68pr3KPIZ1Kd7bREkbrn12
kXz/Si/PoGZpFWXmwTWx8X1jzhZeRmMMC9+Dyu1NdLBKy5l5GU/P7AQ/e0q3MKPN
xSvrVt3szjnqnAP1jX11GwYSo/gDm1n/FN4eiXrTif1JNwp3F9V/AgMBAAGjgeUw
geIwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB
/wQCMAAwgawGA1UdEQSBpDCBoYIEZ2FybYIKZ2FybS5sb2NhbIIJbG9jYWxob3N0
hwQKxnUxhxAqAQT5AEsXXoAAAAAAAAAEhxD+gAAAAAAAAAIWPv/+yxHIhwQK9/YB
hxD+gAAAAAAAAAIWPv/+WxRvhwRkeIJUhxD9ehFcoeCrEkhDzZZieIJUhxD+gAAA
AAAAAGBnFVzKxAsbhwSsEQABhxD+gAAAAAAAAABCKP/+U3+HMA0GCSqGSIb3DQEB
CwUAA4IBAQBxo48eWMMSYBcPvON8fVURTw58OSuW4iw7GTOCZIluQybXfhg7b/CC
BOHwrW6F+j3iIpgQx5AVofGldGKRcCdqg+uToP6rZQvHkoIGwbkTvFLxSnhrr0rc
4fvkgloVEV2Oyf7lFDES64MKh8U+baXgwyUl++vrwSmTv2BCCAG5XNFN8jvAEHLu
wCB6NY6X2RriUGoBr1dIJeDWjYMLQqBh2m9+8vCLsQ7A7TzDJfF7JxhHV94qZ4c4
LKaBdKxl4UGr6HuRMPapsoQqVWV+ZjZrPf4LSoj3DenNwzOc/Rm3Nya8xDCCLxqu
RgNpSos4SD2WTF1RG2buzmgrsdvd3mWX
-----END CERTIFICATE-----