2021-12-12 11:11:11 +00:00
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// 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 hugolib
import (
"fmt"
"net/http"
"net/http/httptest"
"runtime"
"testing"
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/markup/asciidocext"
"github.com/gohugoio/hugo/markup/pandoc"
"github.com/gohugoio/hugo/markup/rst"
"github.com/gohugoio/hugo/resources/resource_transformers/tocss/dartsass"
)
func TestSecurityPolicies ( t * testing . T ) {
c := qt . New ( t )
testVariant := func ( c * qt . C , withBuilder func ( b * sitesBuilder ) , expectErr string ) {
c . Helper ( )
b := newTestSitesBuilder ( c )
withBuilder ( b )
if expectErr != "" {
err := b . BuildE ( BuildCfg { } )
b . Assert ( err , qt . IsNotNil )
b . Assert ( err , qt . ErrorMatches , expectErr )
} else {
b . Build ( BuildCfg { } )
}
}
httpTestVariant := func ( c * qt . C , templ , expectErr string , withBuilder func ( b * sitesBuilder ) ) {
ts := httptest . NewServer ( http . FileServer ( http . Dir ( "testdata/" ) ) )
c . Cleanup ( func ( ) {
ts . Close ( )
} )
cb := func ( b * sitesBuilder ) {
b . WithTemplatesAdded ( "index.html" , fmt . Sprintf ( templ , ts . URL ) )
if withBuilder != nil {
withBuilder ( b )
}
}
testVariant ( c , cb , expectErr )
}
c . Run ( "os.GetEnv, denied" , func ( c * qt . C ) {
c . Parallel ( )
cb := func ( b * sitesBuilder ) {
b . WithTemplatesAdded ( "index.html" , ` {{ os .Getenv "FOOBAR" }} ` )
}
testVariant ( c , cb , ` (?s).*"FOOBAR" is not whitelisted in policy "security\.funcs\.getenv".* ` )
} )
c . Run ( "os.GetEnv, OK" , func ( c * qt . C ) {
c . Parallel ( )
cb := func ( b * sitesBuilder ) {
b . WithTemplatesAdded ( "index.html" , ` {{ os .Getenv "HUGO_FOO" }} ` )
}
testVariant ( c , cb , "" )
} )
c . Run ( "Asciidoc, denied" , func ( c * qt . C ) {
c . Parallel ( )
if ! asciidocext . Supports ( ) {
c . Skip ( )
}
cb := func ( b * sitesBuilder ) {
b . WithContent ( "page.ad" , "foo" )
}
testVariant ( c , cb , ` (?s).*"asciidoctor" is not whitelisted in policy "security\.exec\.allow".* ` )
} )
c . Run ( "RST, denied" , func ( c * qt . C ) {
c . Parallel ( )
if ! rst . Supports ( ) {
c . Skip ( )
}
cb := func ( b * sitesBuilder ) {
b . WithContent ( "page.rst" , "foo" )
}
if runtime . GOOS == "windows" {
testVariant ( c , cb , ` (?s).*python(\.exe)?" is not whitelisted in policy "security\.exec\.allow".* ` )
} else {
testVariant ( c , cb , ` (?s).*"rst2html(\.py)?" is not whitelisted in policy "security\.exec\.allow".* ` )
}
} )
c . Run ( "Pandoc, denied" , func ( c * qt . C ) {
c . Parallel ( )
if ! pandoc . Supports ( ) {
c . Skip ( )
}
cb := func ( b * sitesBuilder ) {
b . WithContent ( "page.pdc" , "foo" )
}
testVariant ( c , cb , ` "(?s).*pandoc" is not whitelisted in policy "security\.exec\.allow".* ` )
} )
c . Run ( "Dart SASS, OK" , func ( c * qt . C ) {
c . Parallel ( )
if ! dartsass . Supports ( ) {
c . Skip ( )
}
cb := func ( b * sitesBuilder ) {
b . WithTemplatesAdded ( "index.html" , ` {{ $scss := "body { color: #333; }" | resources .FromString "foo.scss" | resources .ToCSS ( dict "transpiler" "dartsass" ) }} ` )
}
testVariant ( c , cb , "" )
} )
c . Run ( "Dart SASS, denied" , func ( c * qt . C ) {
c . Parallel ( )
if ! dartsass . Supports ( ) {
c . Skip ( )
}
cb := func ( b * sitesBuilder ) {
b . WithConfigFile ( "toml" , `
[ security ]
[ security . exec ]
allow = "none"
` )
b . WithTemplatesAdded ( "index.html" , ` {{ $scss := "body { color: #333; }" | resources .FromString "foo.scss" | resources .ToCSS ( dict "transpiler" "dartsass" ) }} ` )
}
testVariant ( c , cb , ` (?s).*"dart-sass-embedded" is not whitelisted in policy "security\.exec\.allow".* ` )
} )
2021-12-16 10:09:21 +00:00
c . Run ( "resources.GetRemote, OK" , func ( c * qt . C ) {
2021-12-12 11:11:11 +00:00
c . Parallel ( )
2021-12-16 10:09:21 +00:00
httpTestVariant ( c , ` {{ $json := resources .GetRemote "%[1]s/fruits.json" }} {{ $json .Content }} ` , "" , nil )
2021-12-12 11:11:11 +00:00
} )
2021-12-16 10:09:21 +00:00
c . Run ( "resources.GetRemote, denied method" , func ( c * qt . C ) {
2021-12-12 11:11:11 +00:00
c . Parallel ( )
2021-12-16 10:09:21 +00:00
httpTestVariant ( c , ` {{ $json := resources .GetRemote "%[1]s/fruits.json" ( dict "method" "DELETE" ) }} {{ $json .Content }} ` , ` (?s).*"DELETE" is not whitelisted in policy "security\.http\.method".* ` , nil )
2021-12-12 11:11:11 +00:00
} )
2021-12-16 10:09:21 +00:00
c . Run ( "resources.GetRemote, denied URL" , func ( c * qt . C ) {
2021-12-12 11:11:11 +00:00
c . Parallel ( )
2021-12-16 10:09:21 +00:00
httpTestVariant ( c , ` {{ $json := resources .GetRemote "%[1]s/fruits.json" }} {{ $json .Content }} ` , ` (?s).*is not whitelisted in policy "security\.http\.urls".* ` ,
2021-12-12 11:11:11 +00:00
func ( b * sitesBuilder ) {
b . WithConfigFile ( "toml" , `
[ security ]
[ security . http ]
urls = "none"
` )
} )
} )
c . Run ( "getJSON, OK" , func ( c * qt . C ) {
c . Parallel ( )
httpTestVariant ( c , ` {{ $json := getJSON "%[1]s/fruits.json" }} {{ $json .Content }} ` , "" , nil )
} )
c . Run ( "getJSON, denied URL" , func ( c * qt . C ) {
c . Parallel ( )
httpTestVariant ( c , ` {{ $json := getJSON "%[1]s/fruits.json" }} {{ $json .Content }} ` , ` (?s).*is not whitelisted in policy "security\.http\.urls".* ` ,
func ( b * sitesBuilder ) {
b . WithConfigFile ( "toml" , `
[ security ]
[ security . http ]
urls = "none"
` )
} )
} )
c . Run ( "getCSV, denied URL" , func ( c * qt . C ) {
c . Parallel ( )
httpTestVariant ( c , ` {{ $d := getCSV ";" "%[1]s/cities.csv" }} {{ $d .Content }} ` , ` (?s).*is not whitelisted in policy "security\.http\.urls".* ` ,
func ( b * sitesBuilder ) {
b . WithConfigFile ( "toml" , `
[ security ]
[ security . http ]
urls = "none"
` )
} )
} )
}