Пример #1
0
func TestDistUpgrade(t *testing.T) {
	database.Open(&config.DatabaseConfig{Type: "memstore"})
	defer database.Close()

	_, f, _, _ := runtime.Caller(0)
	path := path.Join(path.Dir(f)) + "/testdata/DistUpgrade/"

	// blank.tar: MAINTAINER Quentin MACHU <quentin.machu.fr>
	// wheezy.tar: FROM debian:wheezy
	// jessie.tar: RUN sed -i "s/precise/trusty/" /etc/apt/sources.list && apt-get update && apt-get -y dist-upgrade
	assert.Nil(t, Process("blank", "", path+"blank.tar.gz", "Docker"))
	assert.Nil(t, Process("wheezy", "blank", path+"wheezy.tar.gz", "Docker"))
	assert.Nil(t, Process("jessie", "wheezy", path+"jessie.tar.gz", "Docker"))

	err := Process("blank", "", path+"blank.tar.gz", "")
	assert.Error(t, err, "could not process a layer which does not have a specified format")

	err = Process("blank", "", path+"blank.tar.gz", "invalid")
	assert.Error(t, err, "could not process a layer which does not have a supported format")

	wheezy, err := database.FindOneLayerByID("wheezy", database.FieldLayerAll)
	if assert.Nil(t, err) {
		assert.Equal(t, "debian:7", wheezy.OS)
		assert.Len(t, wheezy.InstalledPackagesNodes, 52)
		assert.Len(t, wheezy.RemovedPackagesNodes, 0)

		jessie, err := database.FindOneLayerByID("jessie", database.FieldLayerAll)
		if assert.Nil(t, err) {
			assert.Equal(t, "debian:8", jessie.OS)
			assert.Len(t, jessie.InstalledPackagesNodes, 66)
			assert.Len(t, jessie.RemovedPackagesNodes, 44)

			packageNodes, err := jessie.AllPackages()
			if assert.Nil(t, err) {
				// These packages haven't been upgraded
				nonUpgradedPackages := []database.Package{
					database.Package{Name: "libtext-wrapi18n-perl", Version: types.NewVersionUnsafe("0.06-7")},
					database.Package{Name: "libtext-charwidth-perl", Version: types.NewVersionUnsafe("0.04-7")},
					database.Package{Name: "libtext-iconv-perl", Version: types.NewVersionUnsafe("1.7-5")},
					database.Package{Name: "mawk", Version: types.NewVersionUnsafe("1.3.3-17")},
					database.Package{Name: "insserv", Version: types.NewVersionUnsafe("1.14.0-5")},
					database.Package{Name: "db", Version: types.NewVersionUnsafe("5.1.29-5")},
					database.Package{Name: "ustr", Version: types.NewVersionUnsafe("1.0.4-3")},
					database.Package{Name: "xz-utils", Version: types.NewVersionUnsafe("5.1.1alpha+20120614-2")},
				}
				for _, p := range nonUpgradedPackages {
					p.OS = "debian:7"
					assert.Contains(t, packageNodes, p.GetNode(), "Jessie layer doesn't have %s but it should.", p)
				}
				for _, p := range nonUpgradedPackages {
					p.OS = "debian:8"
					assert.NotContains(t, packageNodes, p.GetNode(), "Jessie layer has %s but it shouldn't.", p)
				}
			}
		}
	}
}
Пример #2
0
// Process detects the OS of a layer, the packages it installs/removes, and
// then stores everything in the database.
func Process(ID, parentID, path string) error {
	if ID == "" {
		return cerrors.NewBadRequestError("could not process a layer which does not have ID")
	}
	if path == "" {
		return cerrors.NewBadRequestError("could not process a layer which does not have a path")
	}

	log.Debugf("layer %s: processing (Location: %s, Engine version: %d, Parent: %s)", ID, utils.CleanURL(path), Version, parentID)

	// Check to see if the layer is already in the database.
	layer, err := database.FindOneLayerByID(ID, []string{database.FieldLayerEngineVersion})
	if err != nil && err != cerrors.ErrNotFound {
		return err
	}

	var parent *database.Layer

	if layer != nil {
		// The layer is already in the database, check if we need to update it.
		if layer.EngineVersion >= Version {
			log.Debugf("layer %s: layer content has already been processed in the past with engine %d. Current engine is %d. skipping analysis", ID, layer.EngineVersion, Version)
			return nil
		}

		log.Debugf("layer %s: layer content has been analyzed in the past with engine %d. Current engine is %d. analyzing again", ID, layer.EngineVersion, Version)
	} else {
		// The layer is a new one, create a base struct that we will fill.
		layer = &database.Layer{ID: ID, EngineVersion: Version}

		// Check to make sure that the parent's layer has already been processed.
		if parentID != "" {
			parent, err = database.FindOneLayerByID(parentID, []string{database.FieldLayerOS, database.FieldLayerPackages, database.FieldLayerPackages})
			if err != nil && err != cerrors.ErrNotFound {
				return err
			}
			if parent == nil {
				log.Warningf("layer %s: the parent layer (%s) is unknown. it must be processed first", ID, parentID)
				return ErrParentUnknown
			}
			layer.ParentNode = parent.GetNode()
		}
	}

	// Analyze the content.
	layer.OS, layer.InstalledPackagesNodes, layer.RemovedPackagesNodes, err = detectContent(ID, path, parent)
	if err != nil {
		return err
	}

	return database.InsertLayer(layer)
}
Пример #3
0
// GETLayersVulnerabilities returns the complete list of vulnerabilities that
// a layer has if it exists.
func GETLayersVulnerabilities(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	// Get minumum priority parameter.
	minimumPriority := types.Priority(r.URL.Query().Get("minimumPriority"))
	if minimumPriority == "" {
		minimumPriority = "High" // Set default priority to High
	} else if !minimumPriority.IsValid() {
		httputils.WriteHTTPError(w, 0, cerrors.NewBadRequestError("invalid priority"))
		return
	}

	// Find layer
	layer, err := database.FindOneLayerByID(p.ByName("id"), []string{database.FieldLayerParent, database.FieldLayerPackages})
	if err != nil {
		httputils.WriteHTTPError(w, 0, err)
		return
	}

	// Find layer's packages.
	packagesNodes, err := layer.AllPackages()
	if err != nil {
		httputils.WriteHTTPError(w, 0, err)
		return
	}

	// Find vulnerabilities.
	vulnerabilities, err := getVulnerabilitiesFromLayerPackagesNodes(packagesNodes, minimumPriority, []string{database.FieldVulnerabilityID, database.FieldVulnerabilityLink, database.FieldVulnerabilityPriority, database.FieldVulnerabilityDescription, database.FieldVulnerabilityCausedByPackage})
	if err != nil {
		httputils.WriteHTTPError(w, 0, err)
		return
	}

	httputils.WriteHTTP(w, http.StatusOK, struct{ Vulnerabilities []*database.Vulnerability }{Vulnerabilities: vulnerabilities})
}
Пример #4
0
// GETLayersPackagesDiff returns the list of packages that a layer installs and
// removes if it exists.
func GETLayersPackagesDiff(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	// Find layer.
	layer, err := database.FindOneLayerByID(p.ByName("id"), []string{database.FieldLayerPackages})
	if err != nil {
		httputils.WriteHTTPError(w, 0, err)
		return
	}

	// Find layer's packages.
	installedPackages, removedPackages := make([]*database.Package, 0), make([]*database.Package, 0)
	if len(layer.InstalledPackagesNodes) > 0 {
		installedPackages, err = database.FindAllPackagesByNodes(layer.InstalledPackagesNodes, []string{database.FieldPackageOS, database.FieldPackageName, database.FieldPackageVersion})
		if err != nil {
			httputils.WriteHTTPError(w, 0, err)
			return
		}
	}
	if len(layer.RemovedPackagesNodes) > 0 {
		removedPackages, err = database.FindAllPackagesByNodes(layer.RemovedPackagesNodes, []string{database.FieldPackageOS, database.FieldPackageName, database.FieldPackageVersion})
		if err != nil {
			httputils.WriteHTTPError(w, 0, err)
			return
		}
	}

	httputils.WriteHTTP(w, http.StatusOK, struct{ InstalledPackages, RemovedPackages []*database.Package }{InstalledPackages: installedPackages, RemovedPackages: removedPackages})
}
Пример #5
0
// GETLayersPackages returns the complete list of packages that a layer has
// if it exists.
func GETLayersPackages(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	// Find layer
	layer, err := database.FindOneLayerByID(p.ByName("id"), []string{database.FieldLayerParent, database.FieldLayerPackages})
	if err != nil {
		httputils.WriteHTTPError(w, 0, err)
		return
	}

	// Find layer's packages.
	packagesNodes, err := layer.AllPackages()
	if err != nil {
		httputils.WriteHTTPError(w, 0, err)
		return
	}

	packages := []*database.Package{}
	if len(packagesNodes) > 0 {
		packages, err = database.FindAllPackagesByNodes(packagesNodes, []string{database.FieldPackageOS, database.FieldPackageName, database.FieldPackageVersion})
		if err != nil {
			httputils.WriteHTTPError(w, 0, err)
			return
		}
	}

	httputils.WriteHTTP(w, http.StatusOK, struct{ Packages []*database.Package }{Packages: packages})
}
Пример #6
0
// POSTBatchLayersVulnerabilities returns the complete list of vulnerabilities
// that the provided layers have, if they all exist.
func POSTBatchLayersVulnerabilities(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	// Parse body
	var parameters POSTBatchLayersVulnerabilitiesParameters
	if s, err := httputils.ParseHTTPBody(r, &parameters); err != nil {
		httputils.WriteHTTPError(w, s, err)
		return
	}
	if len(parameters.LayersIDs) == 0 {
		httputils.WriteHTTPError(w, http.StatusBadRequest, errors.New("at least one LayerID query parameter must be provided"))
		return
	}

	// Get minumum priority parameter.
	minimumPriority := types.Priority(r.URL.Query().Get("minimumPriority"))
	if minimumPriority == "" {
		minimumPriority = "High" // Set default priority to High
	} else if !minimumPriority.IsValid() {
		httputils.WriteHTTPError(w, 0, cerrors.NewBadRequestError("invalid priority"))
		return
	}

	response := make(map[string]interface{})
	// For each LayerID parameter
	for _, layerID := range parameters.LayersIDs {
		// Find layer
		layer, err := database.FindOneLayerByID(layerID, []string{database.FieldLayerParent, database.FieldLayerPackages})
		if err != nil {
			httputils.WriteHTTPError(w, 0, err)
			return
		}

		// Find layer's packages.
		packagesNodes, err := layer.AllPackages()
		if err != nil {
			httputils.WriteHTTPError(w, 0, err)
			return
		}

		// Find vulnerabilities.
		vulnerabilities, err := getVulnerabilitiesFromLayerPackagesNodes(packagesNodes, minimumPriority, []string{database.FieldVulnerabilityID, database.FieldVulnerabilityLink, database.FieldVulnerabilityPriority, database.FieldVulnerabilityDescription, database.FieldVulnerabilityCausedByPackage})
		if err != nil {
			httputils.WriteHTTPError(w, 0, err)
			return
		}

		response[layerID] = struct{ Vulnerabilities []*database.Vulnerability }{Vulnerabilities: vulnerabilities}
	}

	httputils.WriteHTTP(w, http.StatusOK, response)
}
Пример #7
0
func GetVulns(ID string) ([]*database.Vulnerability, error) {
	layer, err := database.FindOneLayerByID(ID, []string{database.FieldLayerParent, database.FieldLayerPackages})
	if err != nil {
		logrus.Debugf("Cannot get layer: %v", err)
		return nil, err
	}

	packagesNodes, err := layer.AllPackages()
	if err != nil {
		logrus.Debugf("Cannot get packages: %v", err)
		return nil, err
	}

	return getVulnerabilitiesFromLayerPackagesNodes(packagesNodes, types.Priority(clairConf.VulnPriority), []string{database.FieldVulnerabilityID, database.FieldVulnerabilityLink, database.FieldVulnerabilityPriority, database.FieldVulnerabilityDescription})
}
Пример #8
0
// GETLayersOS returns the operating system of a layer if it exists.
// It uses not only the specified layer but also its parent layers if necessary.
// An empty OS string is returned if no OS has been detected.
func GETLayersOS(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	// Find layer.
	layer, err := database.FindOneLayerByID(p.ByName("id"), []string{database.FieldLayerParent, database.FieldLayerOS})
	if err != nil {
		httputils.WriteHTTPError(w, 0, err)
		return
	}

	// Get OS.
	os, err := layer.OperatingSystem()
	if err != nil {
		httputils.WriteHTTPError(w, 0, err)
		return
	}

	httputils.WriteHTTP(w, http.StatusOK, struct{ OS string }{OS: os})
}
Пример #9
0
// GETLayersVulnerabilitiesDiff returns the list of vulnerabilities that a layer
// adds and removes if it exists.
func GETLayersVulnerabilitiesDiff(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	// Get minumum priority parameter.
	minimumPriority := types.Priority(r.URL.Query().Get("minimumPriority"))
	if minimumPriority == "" {
		minimumPriority = "High" // Set default priority to High
	} else if !minimumPriority.IsValid() {
		httputils.WriteHTTPError(w, 0, cerrors.NewBadRequestError("invalid priority"))
		return
	}

	// Find layer.
	layer, err := database.FindOneLayerByID(p.ByName("id"), []string{database.FieldLayerPackages})
	if err != nil {
		httputils.WriteHTTPError(w, 0, err)
		return
	}

	// Selected fields for vulnerabilities.
	selectedFields := []string{database.FieldVulnerabilityID, database.FieldVulnerabilityLink, database.FieldVulnerabilityPriority, database.FieldVulnerabilityDescription, database.FieldVulnerabilityCausedByPackage}

	// Find vulnerabilities for installed packages.
	addedVulnerabilities, err := getVulnerabilitiesFromLayerPackagesNodes(layer.InstalledPackagesNodes, minimumPriority, selectedFields)
	if err != nil {
		httputils.WriteHTTPError(w, 0, err)
		return
	}

	// Find vulnerabilities for removed packages.
	removedVulnerabilities, err := getVulnerabilitiesFromLayerPackagesNodes(layer.RemovedPackagesNodes, minimumPriority, selectedFields)
	if err != nil {
		httputils.WriteHTTPError(w, 0, err)
		return
	}

	// Remove vulnerabilities which appears both in added and removed lists (eg. case of updated packages but still vulnerable).
	for ia, a := range addedVulnerabilities {
		for ir, r := range removedVulnerabilities {
			if a.ID == r.ID {
				addedVulnerabilities = append(addedVulnerabilities[:ia], addedVulnerabilities[ia+1:]...)
				removedVulnerabilities = append(removedVulnerabilities[:ir], removedVulnerabilities[ir+1:]...)
			}
		}
	}

	httputils.WriteHTTP(w, http.StatusOK, struct{ Adds, Removes []*database.Vulnerability }{Adds: addedVulnerabilities, Removes: removedVulnerabilities})
}
Пример #10
0
// GETLayersParent returns the parent ID of a layer if it exists.
// An empty ID string is returned if the layer has no parent.
func GETLayersParent(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	// Find layer
	layer, err := database.FindOneLayerByID(p.ByName("id"), []string{database.FieldLayerParent})
	if err != nil {
		httputils.WriteHTTPError(w, 0, err)
		return
	}

	// Get layer's parent.
	parent, err := layer.Parent([]string{database.FieldLayerID})
	if err != nil {
		httputils.WriteHTTPError(w, 0, err)
		return
	}

	ID := ""
	if parent != nil {
		ID = parent.ID
	}
	httputils.WriteHTTP(w, http.StatusOK, struct{ ID string }{ID: ID})
}
Пример #11
0
func ClairGetVulns(ID string, ParentID string, Path string) ([]*database.Vulnerability, error) {
	// Process data.
	logrus.Debugf("Start to get vulnerabilities: %v %v %v", ID, ParentID, Path)
	if err := worker.Process(ID, ParentID, Path); err != nil {
		logrus.Debugf("End find err process: %v", err)
		return nil, err
	}
	// Find layer
	layer, err := database.FindOneLayerByID(ID, []string{database.FieldLayerParent, database.FieldLayerPackages})
	if err != nil {
		logrus.Debugf("Cannot get layer: %v", err)
		return nil, err
	}

	// Find layer's packages.
	packagesNodes, err := layer.AllPackages()
	if err != nil {
		logrus.Debugf("Cannot get packages: %v", err)
		return nil, err
	}

	// Find vulnerabilities.
	return getVulnerabilitiesFromLayerPackagesNodes(packagesNodes, types.Priority(clairConf.VulnPriority), []string{database.FieldVulnerabilityID, database.FieldVulnerabilityLink, database.FieldVulnerabilityPriority, database.FieldVulnerabilityDescription})
}
Пример #12
0
// POSTVulnerabilitiesAffectedLayers returns whether the specified layers
// (by their IDs) are vulnerable to the given Vulnerability or not.
func POSTVulnerabilitiesAffectedLayers(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	// Parse body.
	var parameters POSTBatchLayersVulnerabilitiesParameters
	if s, err := jsonhttp.ParseBody(r, &parameters); err != nil {
		jsonhttp.RenderError(w, s, err)
		return
	}
	if len(parameters.LayersIDs) == 0 {
		jsonhttp.RenderError(w, http.StatusBadRequest, errors.New("getting the entire list of affected layers is not supported yet: at least one LayerID query parameter must be provided"))
		return
	}

	// Find vulnerability.
	vulnerability, err := database.FindOneVulnerability(p.ByName("id"), []string{database.FieldVulnerabilityFixedIn})
	if err != nil {
		jsonhttp.RenderError(w, 0, err)
		return
	}

	// Save the fixed in nodes into a map for fast check.
	fixedInPackagesMap := make(map[string]struct{})
	for _, fixedInNode := range vulnerability.FixedInNodes {
		fixedInPackagesMap[fixedInNode] = struct{}{}
	}

	response := make(map[string]interface{})
	// For each LayerID parameter.
	for _, layerID := range parameters.LayersIDs {
		// Find layer
		layer, err := database.FindOneLayerByID(layerID, []string{database.FieldLayerParent, database.FieldLayerPackages, database.FieldLayerPackages})
		if err != nil {
			jsonhttp.RenderError(w, 0, err)
			return
		}

		// Find layer's packages.
		packagesNodes, err := layer.AllPackages()
		if err != nil {
			jsonhttp.RenderError(w, 0, err)
			return
		}

		// Get successors packages of layer' packages.
		successors, err := getSuccessorsFromPackagesNodes(packagesNodes)
		if err != nil {
			jsonhttp.RenderError(w, 0, err)
			return
		}

		// Determine if the layer is vulnerable by verifying if one of the successors
		// of its packages are fixed by the vulnerability.
		vulnerable := false
		for _, p := range successors {
			if _, fixed := fixedInPackagesMap[p]; fixed {
				vulnerable = true
				break
			}
		}

		response[layerID] = struct{ Vulnerable bool }{Vulnerable: vulnerable}
	}

	jsonhttp.Render(w, http.StatusOK, response)
}