From 574aa150ac4bf6c932be7dafa5a43eedef081705 Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins Date: Wed, 10 Aug 2022 00:58:37 -0700 Subject: [PATCH 1/8] Support mTLS with client certificate when configured. --- internal/http/http.go | 52 +++++++++++++++++++++++++----------- internal/http/http_test.go | 53 ++++++++++++++++++++++++++----------- internal/http/testcert.pem | 32 ++++++++++++++++++++++ internal/http/testkey.pem | 52 ++++++++++++++++++++++++++++++++++++ pkg/config/config.go | 4 ++- www/docs/static/schema.json | 12 ++++++++- 6 files changed, 172 insertions(+), 33 deletions(-) create mode 100644 internal/http/testcert.pem create mode 100644 internal/http/testkey.pem diff --git a/internal/http/http.go b/internal/http/http.go index 728862c1f51..148c81435e5 100644 --- a/internal/http/http.go +++ b/internal/http/http.go @@ -112,6 +112,19 @@ func CheckConfig(ctx *context.Context, upload *config.Upload, kind string) error return misconfigured(kind, upload, "no certificate could be added from the specified trusted_certificates configuration") } + if upload.ClientX509Cert != "" && upload.ClientX509Key == "" { + return misconfigured(kind, upload, "'client_x509_key' must be set when 'client_x509_cert' is set") + } + if upload.ClientX509Key != "" && upload.ClientX509Cert == "" { + return misconfigured(kind, upload, "'client_x509_cert' must be set when 'client_x509_key' is set") + } + if upload.ClientX509Cert != "" && upload.ClientX509Key != "" { + if _, err := tls.LoadX509KeyPair(upload.ClientX509Cert, upload.ClientX509Key); err != nil { + return misconfigured(kind, upload, + "client x509 certificate could not be loaded from the specified 'client_x509_cert' and 'client_x509_key'") + } + } + return nil } @@ -306,27 +319,34 @@ func newUploadRequest(ctx *context.Context, method, target, username, secret str } func getHTTPClient(upload *config.Upload) (*h.Client, error) { - if upload.TrustedCerts == "" { + if upload.TrustedCerts == "" && upload.ClientX509Cert == "" && upload.ClientX509Key == "" { return h.DefaultClient, nil } - pool, err := x509.SystemCertPool() - if err != nil { - if runtime.GOOS == "windows" { - // on windows ignore errors until golang issues #16736 & #18609 get fixed - pool = x509.NewCertPool() - } else { + transport := &h.Transport{ + Proxy: h.ProxyFromEnvironment, + TLSClientConfig: &tls.Config{}, + } + if upload.TrustedCerts != "" { + pool, err := x509.SystemCertPool() + if err != nil { + if runtime.GOOS == "windows" { + // on windows ignore errors until golang issues #16736 & #18609 get fixed + pool = x509.NewCertPool() + } else { + return nil, err + } + } + pool.AppendCertsFromPEM([]byte(upload.TrustedCerts)) // already validated certs checked by CheckConfig + transport.TLSClientConfig.RootCAs = pool + } + if upload.ClientX509Cert != "" && upload.ClientX509Key != "" { + cert, err := tls.LoadX509KeyPair(upload.ClientX509Cert, upload.ClientX509Key) + if err != nil { return nil, err } + transport.TLSClientConfig.Certificates = []tls.Certificate{cert} } - pool.AppendCertsFromPEM([]byte(upload.TrustedCerts)) // already validated certs checked by CheckConfig - return &h.Client{ - Transport: &h.Transport{ - Proxy: h.ProxyFromEnvironment, - TLSClientConfig: &tls.Config{ // nolint: gosec - RootCAs: pool, - }, - }, - }, nil + return &h.Client{Transport: transport}, nil } // executeHTTPRequest processes the http call with respect of context ctx. diff --git a/internal/http/http_test.go b/internal/http/http_test.go index 1966464a3de..0a5f76d967c 100644 --- a/internal/http/http_test.go +++ b/internal/http/http_test.go @@ -2,6 +2,7 @@ package http import ( "bytes" + "crypto/tls" "encoding/pem" "errors" "fmt" @@ -566,6 +567,26 @@ func TestUpload(t *testing.T) { check{"/blah/2.1.0/a.deb", "u3", "x", content, map[string]string{}}, ), }, + { + name: "client cert", + tryTLS: true, + setup: func(s *httptest.Server) (*context.Context, config.Upload) { + s.TLS.ClientAuth = tls.RequireAnyClientCert + return ctx, config.Upload{ + Mode: ModeArchive, + Name: "a", + Target: s.URL + "/{{.ProjectName}}/{{.Version}}/", + Username: "u3", + TrustedCerts: cert(s), + ClientX509Cert: "testcert.pem", + ClientX509Key: "testkey.pem", + Exts: []string{"deb", "rpm"}, + } + }, + check: checks( + check{"/blah/2.1.0/a.deb", "u3", "x", content, map[string]string{}}, + ), + }, } uploadAndCheck := func(t *testing.T, setup func(*httptest.Server) (*context.Context, config.Upload), wantErrPlain, wantErrTLS bool, check func(r []*h.Request) error, srv *httptest.Server) { @@ -585,21 +606,23 @@ func TestUpload(t *testing.T) { } for _, tt := range tests { - if tt.tryPlain { - t.Run(tt.name, func(t *testing.T) { - srv := httptest.NewServer(mux) - defer srv.Close() - uploadAndCheck(t, tt.setup, tt.wantErrPlain, tt.wantErrTLS, tt.check, srv) - }) - } - if tt.tryTLS { - t.Run(tt.name+"-tls", func(t *testing.T) { - srv := httptest.NewUnstartedServer(mux) - srv.StartTLS() - defer srv.Close() - uploadAndCheck(t, tt.setup, tt.wantErrPlain, tt.wantErrTLS, tt.check, srv) - }) - } + t.Run(tt.name, func(t *testing.T) { + if tt.tryPlain { + t.Run(tt.name, func(t *testing.T) { + srv := httptest.NewServer(mux) + defer srv.Close() + uploadAndCheck(t, tt.setup, tt.wantErrPlain, tt.wantErrTLS, tt.check, srv) + }) + } + if tt.tryTLS { + t.Run(tt.name+"-tls", func(t *testing.T) { + srv := httptest.NewUnstartedServer(mux) + srv.StartTLS() + defer srv.Close() + uploadAndCheck(t, tt.setup, tt.wantErrPlain, tt.wantErrTLS, tt.check, srv) + }) + } + }) } } diff --git a/internal/http/testcert.pem b/internal/http/testcert.pem new file mode 100644 index 00000000000..0d0f35c441c --- /dev/null +++ b/internal/http/testcert.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFgTCCA2mgAwIBAgIUScqw7e1i0RlxSe+l4VSg6cJXjSAwDQYJKoZIhvcNAQEL +BQAwUDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMSEwHwYDVQQKDBhJbnRlcm5l +dCBXaWRnaXRzIFB0eSBMdGQxETAPBgNVBAMMCHRlc3RjZXJ0MB4XDTIyMDgxMDA3 +NTMzN1oXDTIyMDkwOTA3NTMzN1owUDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNB +MSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxETAPBgNVBAMMCHRl +c3RjZXJ0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0I10EpRJapUo +hQrvTvK12utZ1L6UASW7twzN2l4alM/hRi9qyrUUWIhD8uB0oEaPxa8ErAJFuK2e +paNMB7j0bS4iMaaTZx7hh9IoEz8iROiBILt+68LM9zEVN19YbLws6m7IQ7LAcjj8 +imshswzVIDyOArLSko8z81nEE8fAbzXzBRfG5+x4T5JnVTy/B4qNC3Rk5McNfsOj +bTUklsVOeOmsWoNsMZXUgPMKXZbwQ1fJlNEcXalfxWXF7MBVuZD59eKeHZdFCvg9 +otVqdaD4tEDcm9rjd7osNEasdGPSGG6kNIbUE8LYmSTR3OL1oPoQiqi+ic9NUOer +lsUgjbHwH8B0arw7QIbNDLNgIsKJX5FuGfb6BgfWoItrGc2wqFvXAWVn0EmTGCd6 +x7IioW/U4TI+WHKlSZ2PdwtGnEmp0JXzwx3n6XTja30DMZXXTZ4MXd+YdLn7Lajz +33BXm6UYiVpxkCD/3QN2+32SwYWYa/js7rf2gZ3G3lpt4Iqb82v4/p4wxRcUl5sj +ws8yteV15iecXP1ow/wmUfzLBmHQkwy9WD1poKGWL7fVzWpTe4U+lYM47mXznvzu +WkXI2K1/70L+IablW6USDdMolf4ZR8IOS8cXl30z1XP7c+u0V9SGHOLVToOEfGIx +zxgT2P8wfkAiDY/qhNT2R5nMVrSymm8CAwEAAaNTMFEwHQYDVR0OBBYEFABsCi9C +i5QxArCJBWh1R1Tw4ntLMB8GA1UdIwQYMBaAFABsCi9Ci5QxArCJBWh1R1Tw4ntL +MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAEC/KYL0s/GYKtEY +PsDjF+JwJ2dAKf8ZzfykTUTH4MWA1aGVFlRs5K/pbr1r4nPNumhPyw0+q7YNE8oK +0rhL4LarZQNIPWfSybjxyKD4jQJE8qTFnu0imn9r8Lmqjwz6xoz5JPt89dzk8ysR +et7Yv4q0aFDffSTnx2JbabR53TXm6JqTFkEBn66GGyq7ZTVU0yaHUsWsWRBsLFLY +F/gQp+l8uJlEi9MQh0gWPeIUJf+uGryOsOTEpFvYQ/9kaMHaHDQQ4FdKMDpGP4xi +YNvCzn4xQkEX8r5+Kff0Nr9dflsg6TMzPUJwPKqfi6s+mj5AkB2rAiBKO/Yvu5sb +ZLfYiRP73TIj2PSi0OxhADhtBwkhYFzhnNlAF76QieXsRMnwDG0oztTxMKIcIXaW +cCwB637h+BypnR22ye8ObzCRvh7CW841Xb/qNaPsHiviEtPsejeMIXcSwVbk3cU+ +zYPUYrg7+S6/BUQIcYX8sVuPHxmZlDe4Zt/wHn7PhvO7RkHKmEM+WH1snJ/0mxd7 +V++YDMxBdThi33cNsfBT6ug9xEcLydSD+Q+VqOTS+YsrnvpdKl2l/A9pODcCpazn +xR/LjDsbbsHgCP+90tM46ZIS7HV5uT6Gyek/UEergtaNjmA6gFU1C8BPI2NZjn+n +BsplATncX8RY04Q6e6x4FMxLEGCK +-----END CERTIFICATE----- diff --git a/internal/http/testkey.pem b/internal/http/testkey.pem new file mode 100644 index 00000000000..b39a1ae4585 --- /dev/null +++ b/internal/http/testkey.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +xCjEgdOkFCQ01FTbkkb4n7xPsleEas0= +-----END PRIVATE KEY----- diff --git a/pkg/config/config.go b/pkg/config/config.go index 2355cb3f4a6..fafe75973b3 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -864,8 +864,10 @@ type Upload struct { Mode string `yaml:"mode,omitempty" json:"mode,omitempty"` Method string `yaml:"method,omitempty" json:"method,omitempty"` ChecksumHeader string `yaml:"checksum_header,omitempty" json:"checksum_header,omitempty"` + ClientX509Cert string `yaml:"client_x509_cert" json:"client_x509_cert"` + ClientX509Key string `yaml:"client_x509_key" json:"client_x509_key"` TrustedCerts string `yaml:"trusted_certificates,omitempty" json:"trusted_certificates,omitempty"` - Checksum bool `yaml:"checksum,omitempty" json:"checksum,omitempty"` + Checksum bool `yaml:"checksum,omitqempty" json:"checksum,omitempty"` Signature bool `yaml:"signature,omitempty" json:"signature,omitempty"` CustomArtifactName bool `yaml:"custom_artifact_name,omitempty" json:"custom_artifact_name,omitempty"` CustomHeaders map[string]string `yaml:"custom_headers,omitempty" json:"custom_headers,omitempty"` diff --git a/www/docs/static/schema.json b/www/docs/static/schema.json index c7a20ab5d6e..32098e51dcf 100644 --- a/www/docs/static/schema.json +++ b/www/docs/static/schema.json @@ -2508,6 +2508,12 @@ "checksum_header": { "type": "string" }, + "client_x509_cert": { + "type": "string" + }, + "client_x509_key": { + "type": "string" + }, "trusted_certificates": { "type": "string" }, @@ -2530,7 +2536,11 @@ } }, "additionalProperties": false, - "type": "object" + "type": "object", + "required": [ + "client_x509_cert", + "client_x509_key" + ] }, "Webhook": { "properties": { From d3b5758863d28913322c9756eb007d968e3c8e65 Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins Date: Wed, 10 Aug 2022 10:15:45 -0700 Subject: [PATCH 2/8] Fix the omitempty typo. --- pkg/config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index fafe75973b3..5d834dd8964 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -867,7 +867,7 @@ type Upload struct { ClientX509Cert string `yaml:"client_x509_cert" json:"client_x509_cert"` ClientX509Key string `yaml:"client_x509_key" json:"client_x509_key"` TrustedCerts string `yaml:"trusted_certificates,omitempty" json:"trusted_certificates,omitempty"` - Checksum bool `yaml:"checksum,omitqempty" json:"checksum,omitempty"` + Checksum bool `yaml:"checksum,omitempty" json:"checksum,omitempty"` Signature bool `yaml:"signature,omitempty" json:"signature,omitempty"` CustomArtifactName bool `yaml:"custom_artifact_name,omitempty" json:"custom_artifact_name,omitempty"` CustomHeaders map[string]string `yaml:"custom_headers,omitempty" json:"custom_headers,omitempty"` From 20d3fb5b2980e9984d13ffa6bbe087111f25e36f Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins Date: Wed, 10 Aug 2022 10:49:16 -0700 Subject: [PATCH 3/8] Add check for missing cert as well. --- internal/http/http_test.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/internal/http/http_test.go b/internal/http/http_test.go index 0a5f76d967c..b5296f8bfd2 100644 --- a/internal/http/http_test.go +++ b/internal/http/http_test.go @@ -568,7 +568,9 @@ func TestUpload(t *testing.T) { ), }, { - name: "client cert", + name: "given a server with ClientAuth = RequireAnyClientCert, " + + "and an Upload with ClientX509Cert and ClientX509Key set, " + + "then the response should pass", tryTLS: true, setup: func(s *httptest.Server) (*context.Context, config.Upload) { s.TLS.ClientAuth = tls.RequireAnyClientCert @@ -587,6 +589,25 @@ func TestUpload(t *testing.T) { check{"/blah/2.1.0/a.deb", "u3", "x", content, map[string]string{}}, ), }, + { + name: "given a server with ClientAuth = RequireAnyClientCert, " + + "and an Upload without either ClientX509Cert or ClientX509Key set, " + + "then the response should fail", + tryTLS: true, + setup: func(s *httptest.Server) (*context.Context, config.Upload) { + s.TLS.ClientAuth = tls.RequireAnyClientCert + return ctx, config.Upload{ + Mode: ModeArchive, + Name: "a", + Target: s.URL + "/{{.ProjectName}}/{{.Version}}/", + Username: "u3", + TrustedCerts: cert(s), + Exts: []string{"deb", "rpm"}, + } + }, + wantErrTLS: true, + check: checks(), + }, } uploadAndCheck := func(t *testing.T, setup func(*httptest.Server) (*context.Context, config.Upload), wantErrPlain, wantErrTLS bool, check func(r []*h.Request) error, srv *httptest.Server) { From 00fb55686bf5a77357a32af03ffc0112c3c8d71e Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins Date: Wed, 10 Aug 2022 12:42:26 -0700 Subject: [PATCH 4/8] Added documentation for artifactory and upload, as well as how to run mkdocs locally --- www/Pipfile | 15 ++ www/Pipfile.lock | 298 ++++++++++++++++++++++++++ www/README.md | 41 ++++ www/docs/customization/artifactory.md | 18 +- www/docs/customization/upload.md | 23 +- 5 files changed, 393 insertions(+), 2 deletions(-) create mode 100644 www/Pipfile create mode 100644 www/Pipfile.lock create mode 100644 www/README.md diff --git a/www/Pipfile b/www/Pipfile new file mode 100644 index 00000000000..aed8ff9a6ab --- /dev/null +++ b/www/Pipfile @@ -0,0 +1,15 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +mkdocs = "*" +pymdown-extensions = "*" +mkdocs-material = "*" +mkdocs-minify-plugin = "*" + +[dev-packages] + +[requires] +python_version = "3.8" diff --git a/www/Pipfile.lock b/www/Pipfile.lock new file mode 100644 index 00000000000..abb89df86dd --- /dev/null +++ b/www/Pipfile.lock @@ -0,0 +1,298 @@ +{ + "_meta": { + "hash": { + "sha256": "439a9659102cbe6dddcb9663328126103786c626aebe6005788c036242d12f7d" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.8" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "click": { + "hashes": [ + "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", + "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" + ], + "markers": "python_version >= '3.7'", + "version": "==8.1.3" + }, + "csscompressor": { + "hashes": [ + "sha256:afa22badbcf3120a4f392e4d22f9fff485c044a1feda4a950ecc5eba9dd31a05" + ], + "version": "==0.9.5" + }, + "ghp-import": { + "hashes": [ + "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", + "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343" + ], + "version": "==2.1.0" + }, + "htmlmin": { + "hashes": [ + "sha256:50c1ef4630374a5d723900096a961cff426dff46b48f34d194a81bbe14eca178" + ], + "version": "==0.1.12" + }, + "importlib-metadata": { + "hashes": [ + "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670", + "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23" + ], + "markers": "python_version >= '3.7'", + "version": "==4.12.0" + }, + "jinja2": { + "hashes": [ + "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", + "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" + ], + "markers": "python_version >= '3.7'", + "version": "==3.1.2" + }, + "jsmin": { + "hashes": [ + "sha256:c0959a121ef94542e807a674142606f7e90214a2b3d1eb17300244bbb5cc2bfc" + ], + "version": "==3.0.1" + }, + "markdown": { + "hashes": [ + "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874", + "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621" + ], + "markers": "python_version >= '3.6'", + "version": "==3.3.7" + }, + "markupsafe": { + "hashes": [ + "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003", + "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88", + "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5", + "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7", + "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a", + "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603", + "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1", + "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135", + "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247", + "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6", + "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601", + "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77", + "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02", + "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e", + "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63", + "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f", + "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980", + "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b", + "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812", + "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff", + "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96", + "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1", + "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925", + "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a", + "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6", + "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e", + "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f", + "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4", + "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f", + "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3", + "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c", + "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a", + "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417", + "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a", + "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a", + "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37", + "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452", + "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933", + "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a", + "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7" + ], + "markers": "python_version >= '3.7'", + "version": "==2.1.1" + }, + "mergedeep": { + "hashes": [ + "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", + "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307" + ], + "markers": "python_version >= '3.6'", + "version": "==1.3.4" + }, + "mkdocs": { + "hashes": [ + "sha256:a41a2ff25ce3bbacc953f9844ba07d106233cd76c88bac1f59cb1564ac0d87ed", + "sha256:fda92466393127d2da830bc6edc3a625a14b436316d1caf347690648e774c4f0" + ], + "index": "pypi", + "version": "==1.3.1" + }, + "mkdocs-material": { + "hashes": [ + "sha256:263f2721f3abe533b61f7c8bed435a0462620912742c919821ac2d698b4bfe67", + "sha256:dc82b667d2a83f0de581b46a6d0949732ab77e7638b87ea35b770b33bc02e75a" + ], + "index": "pypi", + "version": "==8.3.9" + }, + "mkdocs-material-extensions": { + "hashes": [ + "sha256:a82b70e533ce060b2a5d9eb2bc2e1be201cf61f901f93704b4acf6e3d5983a44", + "sha256:bfd24dfdef7b41c312ede42648f9eb83476ea168ec163b613f9abd12bbfddba2" + ], + "markers": "python_version >= '3.6'", + "version": "==1.0.3" + }, + "mkdocs-minify-plugin": { + "hashes": [ + "sha256:32d9e8fbd89327a0f4f648f517297aad344c1bad64cfde110d059bd2f2780a6d", + "sha256:487c31ae6b8b3230f56910ce6bcf5c7e6ad9a8c4f51c720a4b989f30c2b0233f" + ], + "index": "pypi", + "version": "==0.5.0" + }, + "packaging": { + "hashes": [ + "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", + "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" + ], + "markers": "python_version >= '3.6'", + "version": "==21.3" + }, + "pygments": { + "hashes": [ + "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb", + "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519" + ], + "markers": "python_version >= '3.6'", + "version": "==2.12.0" + }, + "pymdown-extensions": { + "hashes": [ + "sha256:3ef2d998c0d5fa7eb09291926d90d69391283561cf6306f85cd588a5eb5befa0", + "sha256:ec141c0f4983755349f0c8710416348d1a13753976c028186ed14f190c8061c4" + ], + "index": "pypi", + "version": "==9.5" + }, + "pyparsing": { + "hashes": [ + "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb", + "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc" + ], + "markers": "python_full_version >= '3.6.8'", + "version": "==3.0.9" + }, + "python-dateutil": { + "hashes": [ + "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", + "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.8.2" + }, + "pyyaml": { + "hashes": [ + "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", + "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", + "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", + "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", + "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", + "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", + "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", + "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", + "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", + "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", + "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", + "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", + "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", + "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", + "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", + "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", + "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", + "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", + "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", + "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", + "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", + "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", + "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", + "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", + "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", + "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", + "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", + "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", + "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", + "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", + "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", + "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", + "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" + ], + "markers": "python_version >= '3.6'", + "version": "==6.0" + }, + "pyyaml-env-tag": { + "hashes": [ + "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb", + "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069" + ], + "markers": "python_version >= '3.6'", + "version": "==0.1" + }, + "six": { + "hashes": [ + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.16.0" + }, + "watchdog": { + "hashes": [ + "sha256:083171652584e1b8829581f965b9b7723ca5f9a2cd7e20271edf264cfd7c1412", + "sha256:117ffc6ec261639a0209a3252546b12800670d4bf5f84fbd355957a0595fe654", + "sha256:186f6c55abc5e03872ae14c2f294a153ec7292f807af99f57611acc8caa75306", + "sha256:195fc70c6e41237362ba720e9aaf394f8178bfc7fa68207f112d108edef1af33", + "sha256:226b3c6c468ce72051a4c15a4cc2ef317c32590d82ba0b330403cafd98a62cfd", + "sha256:247dcf1df956daa24828bfea5a138d0e7a7c98b1a47cf1fa5b0c3c16241fcbb7", + "sha256:255bb5758f7e89b1a13c05a5bceccec2219f8995a3a4c4d6968fe1de6a3b2892", + "sha256:43ce20ebb36a51f21fa376f76d1d4692452b2527ccd601950d69ed36b9e21609", + "sha256:4f4e1c4aa54fb86316a62a87b3378c025e228178d55481d30d857c6c438897d6", + "sha256:5952135968519e2447a01875a6f5fc8c03190b24d14ee52b0f4b1682259520b1", + "sha256:64a27aed691408a6abd83394b38503e8176f69031ca25d64131d8d640a307591", + "sha256:6b17d302850c8d412784d9246cfe8d7e3af6bcd45f958abb2d08a6f8bedf695d", + "sha256:70af927aa1613ded6a68089a9262a009fbdf819f46d09c1a908d4b36e1ba2b2d", + "sha256:7a833211f49143c3d336729b0020ffd1274078e94b0ae42e22f596999f50279c", + "sha256:8250546a98388cbc00c3ee3cc5cf96799b5a595270dfcfa855491a64b86ef8c3", + "sha256:97f9752208f5154e9e7b76acc8c4f5a58801b338de2af14e7e181ee3b28a5d39", + "sha256:9f05a5f7c12452f6a27203f76779ae3f46fa30f1dd833037ea8cbc2887c60213", + "sha256:a735a990a1095f75ca4f36ea2ef2752c99e6ee997c46b0de507ba40a09bf7330", + "sha256:ad576a565260d8f99d97f2e64b0f97a48228317095908568a9d5c786c829d428", + "sha256:b530ae007a5f5d50b7fbba96634c7ee21abec70dc3e7f0233339c81943848dc1", + "sha256:bfc4d351e6348d6ec51df007432e6fe80adb53fd41183716017026af03427846", + "sha256:d3dda00aca282b26194bdd0adec21e4c21e916956d972369359ba63ade616153", + "sha256:d9820fe47c20c13e3c9dd544d3706a2a26c02b2b43c993b62fcd8011bcc0adb3", + "sha256:ed80a1628cee19f5cfc6bb74e173f1b4189eb532e705e2a13e3250312a62e0c9", + "sha256:ee3e38a6cc050a8830089f79cbec8a3878ec2fe5160cdb2dc8ccb6def8552658" + ], + "markers": "python_version >= '3.6'", + "version": "==2.1.9" + }, + "zipp": { + "hashes": [ + "sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2", + "sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009" + ], + "markers": "python_version >= '3.7'", + "version": "==3.8.1" + } + }, + "develop": {} +} diff --git a/www/README.md b/www/README.md new file mode 100644 index 00000000000..7268efb905f --- /dev/null +++ b/www/README.md @@ -0,0 +1,41 @@ +# Documentation + +Documentation is written in mkdocs and there are a few extensions that allow richer +authoring than markdown. + +To install them and iterate with documentation locally, [pipenv](https://pipenv.pypa.io/en/latest/) may be used to pull +down [mkdocs](https://www.mkdocs.org/) and its extensions + +## Python and pip prerequisite + +- [Install python3](https://www.python.org/downloads/) if not installed +- Install [pip](https://pip.pypa.io/en/stable/installation/) + +## Installing pipenv + +```bash +python3 -m pip install pipenv +``` + +## Installing mkdocs and its dependencies (extensions) + +```bash +python3 -m pipenv sync +``` + +## Launching mkdocs to serve content locally for iteration + +```bash +python3 -m pipenv run mkdocs serve +``` + +You should see something like + +``` +INFO - Documentation built in 4.63 seconds +INFO - [11:54:10] Watching paths for changes: 'docs', 'mkdocs.yml' +INFO - [11:54:10] Serving on http://127.0.0.1:8000/ +``` + +Then, browse to the url listed in this case to ensure your changes look good as you write them +(serve will force a refresh in the browser when it notices updates) diff --git a/www/docs/customization/artifactory.md b/www/docs/customization/artifactory.md index 7867a2c4e9f..4b157c76d86 100644 --- a/www/docs/customization/artifactory.md +++ b/www/docs/customization/artifactory.md @@ -22,7 +22,7 @@ artifactories: Prerequisites: - A running Artifactory instances -- A user + password / API key with grants to upload an artifact +- A user + password / client x509 certificate / API key with grants to upload an artifact ### Target @@ -82,6 +82,22 @@ If your instance is named `production`, you need to store the secret in the environment variable `ARTIFACTORY_PRODUCTION_SECRET`. The name will be transformed to uppercase. +### Client authorization with x509 certificate (mTLS / mutual TLS) + +If your artifactory server supports authorization with mTLS (client certificates), you can provide them by specifying +the location of an x509 certificate/key pair of pem-encode files. + +```yaml +artifactories: + - name: production + target: http://:8081/artifactory/example-repo-local/{{ .ProjectName }}/{{ .Version }}/ + client_x509_cert: path/to/client.cert.pem + client_x509_key: path/to/client.key.pem +``` + +This will offer the client certificate during the TLS handshake, which your artifactory server may use to authenticate +and authorize you to upload. + ### Server authentication You can authenticate your Artifactory TLS server adding a trusted X.509 diff --git a/www/docs/customization/upload.md b/www/docs/customization/upload.md index 57cbc83264b..2cc188fecae 100644 --- a/www/docs/customization/upload.md +++ b/www/docs/customization/upload.md @@ -20,7 +20,12 @@ uploads: Prerequisites: - An HTTP server accepting HTTP requests -- A user + password with grants to upload an artifact using HTTP requests for basic authentication (only if the server requires it) +- A user + password / client x509 certificate / API key with grants to upload an artifact + +!!! note + authentication is optional and may be provided if the server requires it + - user/pass is for Basic Authentication + - client x509 certificate is for mutual TLS authentication (aka "mTLS") ### Target @@ -89,6 +94,22 @@ The name will be transformed to uppercase. This field is optional and is used only for basic http authentication. +### Client authorization with x509 certificate (mTLS / mutual TLS) + +If your artifactory server supports authorization with mTLS (client certificates), you can provide them by specifying +the location of an x509 certificate/key pair of pem-encode files. + +```yaml +uploads: +- name: production + client_x509_cert: path/to/client.cert.pem + client_x509_key: path/to/client.key.pem + target: 'http://some.server/some/path/example-repo-local/{{ .ProjectName }}/{{ .Version }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}{{ .Arm }}{{ end }}' +``` + +This will offer the client certificate during the TLS handshake, which your artifactory server may use to authenticate +and authorize you to upload. + ### Server authentication You can authenticate your TLS server adding a trusted X.509 certificate chain From 9948d7613cd7183163cdff5c32e30f23c9afcbc6 Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins Date: Wed, 10 Aug 2022 12:50:15 -0700 Subject: [PATCH 5/8] set pip version to just 3. --- www/Pipfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/Pipfile b/www/Pipfile index aed8ff9a6ab..6a013a536f0 100644 --- a/www/Pipfile +++ b/www/Pipfile @@ -12,4 +12,4 @@ mkdocs-minify-plugin = "*" [dev-packages] [requires] -python_version = "3.8" +python_version = "3" From 03e7cefcdd3b684e9d034f62571c75ae099c09ce Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins Date: Wed, 10 Aug 2022 12:53:37 -0700 Subject: [PATCH 6/8] Added example to the full config. --- www/docs/customization/artifactory.md | 4 ++++ www/docs/customization/upload.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/www/docs/customization/artifactory.md b/www/docs/customization/artifactory.md index 4b157c76d86..20d492c239c 100644 --- a/www/docs/customization/artifactory.md +++ b/www/docs/customization/artifactory.md @@ -164,6 +164,10 @@ artifactories: # User that will be used for the deployment username: deployuser + # Client certificate and key (when provided, added as client cert to TLS connections) + client_x509_cert: /path/to/client.cert.pem + client_x509_key: /path/to/client.key.pem + # Upload checksums (defaults to false) checksum: true diff --git a/www/docs/customization/upload.md b/www/docs/customization/upload.md index 2cc188fecae..d8b80d53d73 100644 --- a/www/docs/customization/upload.md +++ b/www/docs/customization/upload.md @@ -187,6 +187,10 @@ uploads: # An optional username that will be used for the deployment for basic authn username: deployuser + # Client certificate and key (when provided, added as client cert to TLS connections) + client_x509_cert: /path/to/client.cert.pem + client_x509_key: /path/to/client.key.pem + # An optional header you can use to tell GoReleaser to pass the artifact's # SHA256 checksum within the upload request. # Default is empty. From e5968477cd503d7f560df746819b943bc85e81a1 Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins Date: Wed, 10 Aug 2022 23:37:47 -0700 Subject: [PATCH 7/8] Remove the Pipfile and update documentation to mention the task. --- www/Pipfile | 15 --- www/Pipfile.lock | 298 ----------------------------------------------- www/README.md | 38 ++---- 3 files changed, 9 insertions(+), 342 deletions(-) delete mode 100644 www/Pipfile delete mode 100644 www/Pipfile.lock diff --git a/www/Pipfile b/www/Pipfile deleted file mode 100644 index 6a013a536f0..00000000000 --- a/www/Pipfile +++ /dev/null @@ -1,15 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -mkdocs = "*" -pymdown-extensions = "*" -mkdocs-material = "*" -mkdocs-minify-plugin = "*" - -[dev-packages] - -[requires] -python_version = "3" diff --git a/www/Pipfile.lock b/www/Pipfile.lock deleted file mode 100644 index abb89df86dd..00000000000 --- a/www/Pipfile.lock +++ /dev/null @@ -1,298 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "439a9659102cbe6dddcb9663328126103786c626aebe6005788c036242d12f7d" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.8" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "click": { - "hashes": [ - "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", - "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" - ], - "markers": "python_version >= '3.7'", - "version": "==8.1.3" - }, - "csscompressor": { - "hashes": [ - "sha256:afa22badbcf3120a4f392e4d22f9fff485c044a1feda4a950ecc5eba9dd31a05" - ], - "version": "==0.9.5" - }, - "ghp-import": { - "hashes": [ - "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", - "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343" - ], - "version": "==2.1.0" - }, - "htmlmin": { - "hashes": [ - "sha256:50c1ef4630374a5d723900096a961cff426dff46b48f34d194a81bbe14eca178" - ], - "version": "==0.1.12" - }, - "importlib-metadata": { - "hashes": [ - "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670", - "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23" - ], - "markers": "python_version >= '3.7'", - "version": "==4.12.0" - }, - "jinja2": { - "hashes": [ - "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", - "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" - ], - "markers": "python_version >= '3.7'", - "version": "==3.1.2" - }, - "jsmin": { - "hashes": [ - "sha256:c0959a121ef94542e807a674142606f7e90214a2b3d1eb17300244bbb5cc2bfc" - ], - "version": "==3.0.1" - }, - "markdown": { - "hashes": [ - "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874", - "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621" - ], - "markers": "python_version >= '3.6'", - "version": "==3.3.7" - }, - "markupsafe": { - "hashes": [ - "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003", - "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88", - "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5", - "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7", - "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a", - "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603", - "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1", - "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135", - "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247", - "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6", - "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601", - "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77", - "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02", - "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e", - "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63", - "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f", - "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980", - "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b", - "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812", - "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff", - "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96", - "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1", - "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925", - "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a", - "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6", - "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e", - "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f", - "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4", - "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f", - "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3", - "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c", - "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a", - "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417", - "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a", - "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a", - "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37", - "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452", - "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933", - "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a", - "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7" - ], - "markers": "python_version >= '3.7'", - "version": "==2.1.1" - }, - "mergedeep": { - "hashes": [ - "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", - "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307" - ], - "markers": "python_version >= '3.6'", - "version": "==1.3.4" - }, - "mkdocs": { - "hashes": [ - "sha256:a41a2ff25ce3bbacc953f9844ba07d106233cd76c88bac1f59cb1564ac0d87ed", - "sha256:fda92466393127d2da830bc6edc3a625a14b436316d1caf347690648e774c4f0" - ], - "index": "pypi", - "version": "==1.3.1" - }, - "mkdocs-material": { - "hashes": [ - "sha256:263f2721f3abe533b61f7c8bed435a0462620912742c919821ac2d698b4bfe67", - "sha256:dc82b667d2a83f0de581b46a6d0949732ab77e7638b87ea35b770b33bc02e75a" - ], - "index": "pypi", - "version": "==8.3.9" - }, - "mkdocs-material-extensions": { - "hashes": [ - "sha256:a82b70e533ce060b2a5d9eb2bc2e1be201cf61f901f93704b4acf6e3d5983a44", - "sha256:bfd24dfdef7b41c312ede42648f9eb83476ea168ec163b613f9abd12bbfddba2" - ], - "markers": "python_version >= '3.6'", - "version": "==1.0.3" - }, - "mkdocs-minify-plugin": { - "hashes": [ - "sha256:32d9e8fbd89327a0f4f648f517297aad344c1bad64cfde110d059bd2f2780a6d", - "sha256:487c31ae6b8b3230f56910ce6bcf5c7e6ad9a8c4f51c720a4b989f30c2b0233f" - ], - "index": "pypi", - "version": "==0.5.0" - }, - "packaging": { - "hashes": [ - "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", - "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" - ], - "markers": "python_version >= '3.6'", - "version": "==21.3" - }, - "pygments": { - "hashes": [ - "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb", - "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519" - ], - "markers": "python_version >= '3.6'", - "version": "==2.12.0" - }, - "pymdown-extensions": { - "hashes": [ - "sha256:3ef2d998c0d5fa7eb09291926d90d69391283561cf6306f85cd588a5eb5befa0", - "sha256:ec141c0f4983755349f0c8710416348d1a13753976c028186ed14f190c8061c4" - ], - "index": "pypi", - "version": "==9.5" - }, - "pyparsing": { - "hashes": [ - "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb", - "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc" - ], - "markers": "python_full_version >= '3.6.8'", - "version": "==3.0.9" - }, - "python-dateutil": { - "hashes": [ - "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.8.2" - }, - "pyyaml": { - "hashes": [ - "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", - "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", - "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", - "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", - "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", - "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", - "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", - "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", - "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", - "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", - "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", - "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", - "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", - "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", - "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", - "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", - "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", - "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", - "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", - "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", - "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", - "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", - "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", - "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", - "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", - "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", - "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", - "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", - "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", - "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", - "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", - "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", - "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" - ], - "markers": "python_version >= '3.6'", - "version": "==6.0" - }, - "pyyaml-env-tag": { - "hashes": [ - "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb", - "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069" - ], - "markers": "python_version >= '3.6'", - "version": "==0.1" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" - }, - "watchdog": { - "hashes": [ - "sha256:083171652584e1b8829581f965b9b7723ca5f9a2cd7e20271edf264cfd7c1412", - "sha256:117ffc6ec261639a0209a3252546b12800670d4bf5f84fbd355957a0595fe654", - "sha256:186f6c55abc5e03872ae14c2f294a153ec7292f807af99f57611acc8caa75306", - "sha256:195fc70c6e41237362ba720e9aaf394f8178bfc7fa68207f112d108edef1af33", - "sha256:226b3c6c468ce72051a4c15a4cc2ef317c32590d82ba0b330403cafd98a62cfd", - "sha256:247dcf1df956daa24828bfea5a138d0e7a7c98b1a47cf1fa5b0c3c16241fcbb7", - "sha256:255bb5758f7e89b1a13c05a5bceccec2219f8995a3a4c4d6968fe1de6a3b2892", - "sha256:43ce20ebb36a51f21fa376f76d1d4692452b2527ccd601950d69ed36b9e21609", - "sha256:4f4e1c4aa54fb86316a62a87b3378c025e228178d55481d30d857c6c438897d6", - "sha256:5952135968519e2447a01875a6f5fc8c03190b24d14ee52b0f4b1682259520b1", - "sha256:64a27aed691408a6abd83394b38503e8176f69031ca25d64131d8d640a307591", - "sha256:6b17d302850c8d412784d9246cfe8d7e3af6bcd45f958abb2d08a6f8bedf695d", - "sha256:70af927aa1613ded6a68089a9262a009fbdf819f46d09c1a908d4b36e1ba2b2d", - "sha256:7a833211f49143c3d336729b0020ffd1274078e94b0ae42e22f596999f50279c", - "sha256:8250546a98388cbc00c3ee3cc5cf96799b5a595270dfcfa855491a64b86ef8c3", - "sha256:97f9752208f5154e9e7b76acc8c4f5a58801b338de2af14e7e181ee3b28a5d39", - "sha256:9f05a5f7c12452f6a27203f76779ae3f46fa30f1dd833037ea8cbc2887c60213", - "sha256:a735a990a1095f75ca4f36ea2ef2752c99e6ee997c46b0de507ba40a09bf7330", - "sha256:ad576a565260d8f99d97f2e64b0f97a48228317095908568a9d5c786c829d428", - "sha256:b530ae007a5f5d50b7fbba96634c7ee21abec70dc3e7f0233339c81943848dc1", - "sha256:bfc4d351e6348d6ec51df007432e6fe80adb53fd41183716017026af03427846", - "sha256:d3dda00aca282b26194bdd0adec21e4c21e916956d972369359ba63ade616153", - "sha256:d9820fe47c20c13e3c9dd544d3706a2a26c02b2b43c993b62fcd8011bcc0adb3", - "sha256:ed80a1628cee19f5cfc6bb74e173f1b4189eb532e705e2a13e3250312a62e0c9", - "sha256:ee3e38a6cc050a8830089f79cbec8a3878ec2fe5160cdb2dc8ccb6def8552658" - ], - "markers": "python_version >= '3.6'", - "version": "==2.1.9" - }, - "zipp": { - "hashes": [ - "sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2", - "sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009" - ], - "markers": "python_version >= '3.7'", - "version": "==3.8.1" - } - }, - "develop": {} -} diff --git a/www/README.md b/www/README.md index 7268efb905f..7819a11df86 100644 --- a/www/README.md +++ b/www/README.md @@ -3,39 +3,19 @@ Documentation is written in mkdocs and there are a few extensions that allow richer authoring than markdown. -To install them and iterate with documentation locally, [pipenv](https://pipenv.pypa.io/en/latest/) may be used to pull -down [mkdocs](https://www.mkdocs.org/) and its extensions +To iterate with documentation, therefore, it is recommended to run the mkdocs server and view your pages in a browser. -## Python and pip prerequisite +## Prerequisites -- [Install python3](https://www.python.org/downloads/) if not installed -- Install [pip](https://pip.pypa.io/en/stable/installation/) +- [Get Docker](https://docs.docker.com/get-docker/) +- [Get Task](https://taskfile.dev/installation/) -## Installing pipenv +### NOTE to M1/M2 mac owners -```bash -python3 -m pip install pipenv -``` - -## Installing mkdocs and its dependencies (extensions) - -```bash -python3 -m pipenv sync -``` - -## Launching mkdocs to serve content locally for iteration +If running on an arm64-based mac (M1 or M2, aka "Applie Silicon"), you may find this method quite slow. Until +a multiarch docker images can be built and made available, you may wish to build your own via: ```bash -python3 -m pipenv run mkdocs serve -``` - -You should see something like - -``` -INFO - Documentation built in 4.63 seconds -INFO - [11:54:10] Watching paths for changes: 'docs', 'mkdocs.yml' -INFO - [11:54:10] Serving on http://127.0.0.1:8000/ +git clone git@github.com:squidfunk/mkdocs-material.git +docker build -t docker.io/squidfunk/mkdocs-material . ``` - -Then, browse to the url listed in this case to ensure your changes look good as you write them -(serve will force a refresh in the browser when it notices updates) From 3e7a98b7305083e7d4f1b3da2268e6be0c657425 Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins Date: Wed, 10 Aug 2022 23:42:13 -0700 Subject: [PATCH 8/8] update language in doc about multiarch images. --- www/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/README.md b/www/README.md index 7819a11df86..463757eece6 100644 --- a/www/README.md +++ b/www/README.md @@ -13,7 +13,7 @@ To iterate with documentation, therefore, it is recommended to run the mkdocs se ### NOTE to M1/M2 mac owners If running on an arm64-based mac (M1 or M2, aka "Applie Silicon"), you may find this method quite slow. Until -a multiarch docker images can be built and made available, you may wish to build your own via: +multiarch docker images can be built and made available, you may wish to build your own via: ```bash git clone git@github.com:squidfunk/mkdocs-material.git