func fetchFromGCS()

in internal/collectiondefinition/gcs.go [72:184]


func fetchFromGCS(ctx context.Context, opts FetchOptions) *cdpb.CollectionDefinition {
	bucketName := bucketEnvMap[opts.Env]
	// Do not verify the connection to the Cloud Storage bucket.
	// Public access is enabled for the downloaded files.
	connectParams := &storage.ConnectParameters{
		StorageClient: opts.Client,
		BucketName:    bucketName,
		UserAgent:     configuration.StorageAgentName(),
	}
	bh, ok := storage.ConnectToBucket(ctx, connectParams)
	if !ok {
		return nil
	}

	// Download the collection definition JSON file.
	// From the Google Cloud Storage docs:
	// Typically, a Reader computes the CRC of the downloaded content
	// and compares it to the stored CRC, returning an error from Read
	// if there is a mismatch.
	cdJSON, err := opts.CreateTemp("", "collection-definition.*.json")
	if err != nil {
		log.CtxLogger(ctx).Warnw("Could not create temporary JSON file", "error", err)
		return nil
	}
	defer os.Remove(cdJSON.Name())
	defer cdJSON.Close()
	rw1 := storage.ReadWriter{
		Writer:                        cdJSON,
		BucketHandle:                  bh,
		Copier:                        io.Copy,
		BucketName:                    bucketName,
		ObjectName:                    "sapagent/collection-definition/collection_definition.json",
		MaxRetries:                    1,
		ParallelDownloadConnectParams: connectParams,
	}
	if _, err = rw1.Download(ctx); err != nil {
		log.CtxLogger(ctx).Warnw("Could not download from cloud storage", "objectName", rw1.ObjectName, "error", err)
		return nil
	}

	// Download the signature file.
	cdSignature, err := opts.CreateTemp("", "collection-definition.*.signature")
	if err != nil {
		log.CtxLogger(ctx).Warnw("Could not create temporary signature file", "error", err)
		return nil
	}
	defer os.Remove(cdSignature.Name())
	defer cdSignature.Close()
	rw2 := storage.ReadWriter{
		Writer:                        cdSignature,
		BucketHandle:                  bh,
		Copier:                        io.Copy,
		BucketName:                    bucketName,
		ObjectName:                    "sapagent/collection-definition/collection_definition.signature",
		MaxRetries:                    1,
		ParallelDownloadConnectParams: connectParams,
	}
	if _, err = rw2.Download(ctx); err != nil {
		log.CtxLogger(ctx).Warnw("Could not download from cloud storage", "objectName", rw2.ObjectName, "error", err)
		return nil
	}

	// Verify using the public key embedded in the agent.
	cdPub, err := opts.CreateTemp("", "public.*.pem")
	if err != nil {
		log.CtxLogger(ctx).Warnw("Could not create temporary public key file", "error", err)
		return nil
	}

	pkey := pubkey
	if opts.Env == cpb.TargetEnvironment_DEVELOPMENT || opts.Env == cpb.TargetEnvironment_INTEGRATION {
		pkey = pubkeyDev
	}
	if _, err = cdPub.Write(pkey); err != nil {
		log.CtxLogger(ctx).Warnw("Could not write public key to temp file", "error", err)
		return nil
	}
	defer os.Remove(cdPub.Name())
	defer cdPub.Close()
	if opts.OSType == "windows" {
		// TODO: Windows verification of downloaded content
		log.CtxLogger(ctx).Warn("Windows signature verification is not supported")
		return nil
	}
	result := opts.Execute(ctx, commandlineexecutor.Params{
		Executable:  "openssl",
		ArgsToSplit: fmt.Sprintf("dgst -sha256 -verify %s -signature %s %s", cdPub.Name(), cdSignature.Name(), cdJSON.Name()),
	})
	if strings.TrimSpace(result.StdOut) != "Verified OK" {
		log.CtxLogger(ctx).Warnw("Could not verify downloaded content for collection definition", "stdout", result.StdOut, "stderr", result.StdErr)
		return nil
	}

	// Read and unmarshal the file as a collection definition.
	stat, err := cdJSON.Stat()
	if err != nil {
		log.CtxLogger(ctx).Warn(err)
		return nil
	}
	b := make([]byte, stat.Size())
	if _, err = cdJSON.ReadAt(b, 0); err != nil && err != io.EOF {
		log.CtxLogger(ctx).Warn(err)
		return nil
	}
	cd, err := unmarshal(b)
	if err != nil {
		log.CtxLogger(ctx).Warn(err)
		return nil
	}

	log.CtxLogger(ctx).Info("Successfully downloaded and verified collection definition")
	return cd
}