Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Heartbeat]: ensure synthetics version compatability for suites #24777

Merged
merged 10 commits into from
Apr 21, 2021
60 changes: 30 additions & 30 deletions NOTICE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2182,6 +2182,36 @@ Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/auto
limitations under the License.


--------------------------------------------------------------------------------
Dependency : github.com/Masterminds/semver
Version: v1.4.2
Licence type (autodetected): MIT
--------------------------------------------------------------------------------

Contents of probable licence file $GOMODCACHE/github.com/!masterminds/[email protected]/LICENSE.txt:

The Masterminds
Copyright (C) 2014-2015, Matt Butcher and Matt Farina

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


--------------------------------------------------------------------------------
Dependency : github.com/bi-zone/go-winio
Version: v0.4.15
Expand Down Expand Up @@ -21031,36 +21061,6 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


--------------------------------------------------------------------------------
Dependency : github.com/Masterminds/semver
Version: v1.4.2
Licence type (autodetected): MIT
--------------------------------------------------------------------------------

Contents of probable licence file $GOMODCACHE/github.com/!masterminds/[email protected]/LICENSE.txt:

The Masterminds
Copyright (C) 2014-2015, Matt Butcher and Matt Farina

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


--------------------------------------------------------------------------------
Dependency : github.com/Microsoft/hcsshim
Version: v0.8.7
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ require (
github.com/Azure/go-autorest/autorest/adal v0.8.2
github.com/Azure/go-autorest/autorest/azure/auth v0.4.2
github.com/Azure/go-autorest/autorest/date v0.2.0
github.com/Masterminds/semver v1.4.2
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5
github.com/Shopify/sarama v1.27.0
github.com/StackExchange/wmi v0.0.0-20170221213301-9f32b5905fd6
Expand Down
7 changes: 7 additions & 0 deletions x-pack/heartbeat/monitors/browser/synthexec/synthexec.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"io"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
"strings"
Expand All @@ -28,6 +29,12 @@ const debugSelector = "synthexec"

// SuiteJob will run a single journey by name from the given suite.
func SuiteJob(ctx context.Context, suitePath string, params common.MapStr, extraArgs ...string) (jobs.Job, error) {
// ensure the used synthetics version dep used in suite does not
// exceed our supported range
err := validatePackageJSON(path.Join(suitePath, "package.json"))
if err != nil {
return nil, err
}
// Run the command in the given suitePath, use '.' as the first arg since the command runs
// in the correct dir
newCmd, err := suiteCommandFactory(suitePath, append(extraArgs, ".", "--screenshots")...)
Expand Down
83 changes: 83 additions & 0 deletions x-pack/heartbeat/monitors/browser/synthexec/validatepackage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.

package synthexec

import (
"encoding/json"
"fmt"
"io/ioutil"
"regexp"
"strings"

"github.com/Masterminds/semver"
)

// ensure compatability of synthetics by enforcing the installed
// version never goes beyond this range
const ExpectedSynthVersion = "<2.0.0"

type packageJson struct {
Dependencies struct {
SynthVersion string `json:"@elastic/synthetics"`
} `json:"dependencies"`
DevDependencies struct {
SynthVersion string `json:"@elastic/synthetics"`
} `json:"devDependencies"`
}

var nonNumberRegex = regexp.MustCompile("\\D")

// parsed a given dep version by ignoring all range tags (^, = , >, <)
func parseVersion(version string) string {
dotParts := strings.SplitN(version, ".", 4)

parsed := []string{}
for _, v := range dotParts[:3] {
value := nonNumberRegex.ReplaceAllString(v, "")
parsed = append(parsed, value)
}
return strings.Join(parsed, ".")
}

func validateVersion(expected string, current string) error {
expectedRange, err := semver.NewConstraint(expected)
if err != nil {
return err
}

parsed := parseVersion(current)
currentVersion, err := semver.NewVersion(parsed)
if err != nil {
return fmt.Errorf("error parsing @elastic/synthetics version: '%s' %w", currentVersion, err)
}

isValid := expectedRange.Check(currentVersion)
if !isValid {
return fmt.Errorf("parsed @elastic/synthetics version '%s' is not compatible", current)
}
return nil
}

func validatePackageJSON(path string) error {
pkgData, err := ioutil.ReadFile(path)
if err != nil {
return fmt.Errorf("could not read file '%s': %w", path, err)
}
pkgJson := packageJson{}
err = json.Unmarshal(pkgData, &pkgJson)
if err != nil {
return fmt.Errorf("could not unmarshall @elastic/synthetics version: %w", err)
}

synthVersion := pkgJson.Dependencies.SynthVersion
if synthVersion == "" {
synthVersion = pkgJson.DevDependencies.SynthVersion
}
err = validateVersion(ExpectedSynthVersion, synthVersion)
if err != nil {
return fmt.Errorf("could not validate @elastic/synthetics version: '%s' %w", synthVersion, err)
}
return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.

package synthexec

import (
"fmt"
"testing"

"github.com/stretchr/testify/require"
)

func TestParseVersionVersion(t *testing.T) {
tests := []struct {
given string
expected string
}{{
given: ">2.1.1",
expected: "2.1.1",
},
{
given: "^0.0.1-alpha.preview+123.github",
expected: "0.0.1",
},
{
given: "<=0.0.1-alpha.12",
expected: "0.0.1",
},
{
given: "^1.0.3-beta",
expected: "1.0.3",
},
{
given: "~^1.0.3",
expected: "1.0.3",
},
}
for _, tt := range tests {
t.Run(fmt.Sprintf("expected version %s does not match given %s", tt.expected, tt.given), func(t *testing.T) {
parsed := parseVersion(tt.given)
require.Equal(t, tt.expected, parsed)
})
}
}

func TestValidateVersion(t *testing.T) {
tests := []struct {
expected string
current string
shouldErr bool
}{
{
expected: "<2.0.0",
current: "^1.1.1",
shouldErr: false,
},
{
expected: "<2.0.0",
current: "=2.1.1",
shouldErr: true,
},
{
expected: "<2.0.0",
current: "2.0.0",
shouldErr: true,
},
{
expected: "<1.0.0",
current: "0.0.1-alpha.11",
shouldErr: false,
},
}

for _, tt := range tests {
t.Run(fmt.Sprintf("match expected %s with current %s version", tt.expected, tt.current), func(t *testing.T) {
err := validateVersion(tt.expected, tt.current)
if tt.shouldErr {
require.Error(t, err)
} else {
require.Equal(t, nil, err)
}
})
}
}