utils

package
v2.45.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 18, 2023 License: Apache-2.0 Imports: 28 Imported by: 0

Documentation

Index

Constants

View Source
const (
	EntitlementsMinVersion = "3.66.5"
	ApplicabilityFeatureId = "contextual_analysis"
	AnalyzerManagerZipName = "analyzerManager.zip"

	ErrFailedScannerRun = "failed to run %s scan. Exit code received: %s"
)
View Source
const MissingCveScore = "0"
View Source
const (
	NpmPackageTypeIdentifier = "npm://"
)
View Source
const (
	SeverityDefaultValue = "Medium"
)

Variables

View Source
var CurationOutputFormats = []string{string(Table), string(Json)}
View Source
var Severities = map[string]map[ApplicabilityStatus]*TableSeverity{
	"Critical": {
		Applicable:                {SeverityDetails: formats.SeverityDetails{Severity: "Critical", SeverityNumValue: 15}, /* contains filtered or unexported fields */},
		ApplicabilityUndetermined: {SeverityDetails: formats.SeverityDetails{Severity: "Critical", SeverityNumValue: 14}, /* contains filtered or unexported fields */},
		NotApplicable:             {SeverityDetails: formats.SeverityDetails{Severity: "Critical", SeverityNumValue: 5}, /* contains filtered or unexported fields */},
	},
	"High": {
		Applicable:                {SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 13}, /* contains filtered or unexported fields */},
		ApplicabilityUndetermined: {SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 12}, /* contains filtered or unexported fields */},
		NotApplicable:             {SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 4}, /* contains filtered or unexported fields */},
	},
	"Medium": {
		Applicable:                {SeverityDetails: formats.SeverityDetails{Severity: "Medium", SeverityNumValue: 11}, /* contains filtered or unexported fields */},
		ApplicabilityUndetermined: {SeverityDetails: formats.SeverityDetails{Severity: "Medium", SeverityNumValue: 10}, /* contains filtered or unexported fields */},
		NotApplicable:             {SeverityDetails: formats.SeverityDetails{Severity: "Medium", SeverityNumValue: 3}, /* contains filtered or unexported fields */},
	},
	"Low": {
		Applicable:                {SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 9}, /* contains filtered or unexported fields */},
		ApplicabilityUndetermined: {SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 8}, /* contains filtered or unexported fields */},
		NotApplicable:             {SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 2}, /* contains filtered or unexported fields */},
	},
	"Unknown": {
		Applicable:                {SeverityDetails: formats.SeverityDetails{Severity: "Unknown", SeverityNumValue: 7}, /* contains filtered or unexported fields */},
		ApplicabilityUndetermined: {SeverityDetails: formats.SeverityDetails{Severity: "Unknown", SeverityNumValue: 6}, /* contains filtered or unexported fields */},
		NotApplicable:             {SeverityDetails: formats.SeverityDetails{Severity: "Unknown", SeverityNumValue: 1}, /* contains filtered or unexported fields */},
	},
}

Functions

func AggregateMultipleRunsIntoSingle added in v2.41.5

func AggregateMultipleRunsIntoSingle(runs []*sarif.Run, destination *sarif.Run)

func ApplicabilityRuleIdToCve added in v2.41.6

func ApplicabilityRuleIdToCve(sarifRuleId string) string

func CheckIfFailBuild added in v2.7.0

func CheckIfFailBuild(results []services.ScanResponse) bool

func ConvertSarifReportToString added in v2.44.0

func ConvertSarifReportToString(report *sarif.Report) (sarifStr string, err error)

func ConvertToSarifLevel added in v2.41.5

func ConvertToSarifLevel(severity string) string

func CreateCodeFlow added in v2.44.0

func CreateCodeFlow(threadFlows ...*sarif.ThreadFlow) *sarif.CodeFlow

func CreateDummyPassingResult added in v2.44.0

func CreateDummyPassingResult(ruleId string) *sarif.Result

func CreateLocation added in v2.44.0

func CreateLocation(fileName string, startLine, startCol, endLine, endCol int, snippet string) *sarif.Location

func CreateResultWithLocations added in v2.44.0

func CreateResultWithLocations(msg, ruleId, level string, locations ...*sarif.Location) *sarif.Result

func CreateResultWithOneLocation added in v2.44.0

func CreateResultWithOneLocation(fileName string, startLine, startCol, endLine, endCol int, snippet, ruleId, level string) *sarif.Result

func CreateRunWithDummyResults added in v2.44.0

func CreateRunWithDummyResults(results ...*sarif.Result) *sarif.Run

func CreateThreadFlow added in v2.44.0

func CreateThreadFlow(locations ...*sarif.Location) *sarif.ThreadFlow

func CreateXrayServiceManager added in v2.41.5

func CreateXrayServiceManager(serviceDetails *config.ServerDetails) (*xray.XrayServicesManager, error)

func CreateXrayServiceManagerAndGetVersion added in v2.41.5

func CreateXrayServiceManagerAndGetVersion(serviceDetails *config.ServerDetails) (*xray.XrayServicesManager, string, error)

func CveToApplicabilityRuleId added in v2.41.6

func CveToApplicabilityRuleId(cveId string) string

func ExtractRelativePath added in v2.36.0

func ExtractRelativePath(resultPath string, projectRoot string) string

func GenereateSarifReportFromResults added in v2.44.0

func GenereateSarifReportFromResults(extendedResults *ExtendedScanResults, isMultipleRoots, includeLicenses bool) (report *sarif.Report, err error)

func GetAnalyzerManagerDirAbsolutePath added in v2.34.1

func GetAnalyzerManagerDirAbsolutePath() (string, error)

func GetAnalyzerManagerDownloadPath added in v2.34.1

func GetAnalyzerManagerDownloadPath() (string, error)

func GetAnalyzerManagerExecutable added in v2.41.0

func GetAnalyzerManagerExecutable() (analyzerManagerPath string, err error)

func GetAnalyzerManagerExecutableName added in v2.34.1

func GetAnalyzerManagerExecutableName() string

func GetAnalyzerManagerVersion added in v2.41.5

func GetAnalyzerManagerVersion() string

func GetFullLocationFileName added in v2.44.0

func GetFullLocationFileName(relative string, invocations []*sarif.Invocation) string

func GetInvocationWorkingDirectory added in v2.41.5

func GetInvocationWorkingDirectory(invocation *sarif.Invocation) string

func GetIssueIdentifier added in v2.43.0

func GetIssueIdentifier(cvesRow []formats.CveRow, issueId string) string

func GetLocationEndColumn added in v2.41.5

func GetLocationEndColumn(location *sarif.Location) int

func GetLocationEndLine added in v2.41.5

func GetLocationEndLine(location *sarif.Location) int

func GetLocationFileName added in v2.41.5

func GetLocationFileName(location *sarif.Location) string

func GetLocationRelatedCodeFlowsFromResult added in v2.41.5

func GetLocationRelatedCodeFlowsFromResult(location *sarif.Location, result *sarif.Result) (codeFlows []*sarif.CodeFlow)

func GetLocationSnippet added in v2.41.5

func GetLocationSnippet(location *sarif.Location) string

func GetLocationStartColumn added in v2.41.5

func GetLocationStartColumn(location *sarif.Location) int

func GetLocationStartLine added in v2.41.5

func GetLocationStartLine(location *sarif.Location) int

func GetRelativeLocationFileName added in v2.41.6

func GetRelativeLocationFileName(location *sarif.Location, invocations []*sarif.Invocation) string

func GetResultMsgText added in v2.41.5

func GetResultMsgText(result *sarif.Result) string

func GetResultSeverity added in v2.36.0

func GetResultSeverity(result *sarif.Result) string

func GetResultsLocationCount added in v2.41.5

func GetResultsLocationCount(runs ...*sarif.Run) (count int)

func GetRuleFullDescription added in v2.41.5

func GetRuleFullDescription(rule *sarif.ReportingDescriptor) string

func GetRunRules added in v2.41.5

func GetRunRules(run *sarif.Run) []*sarif.ReportingDescriptor

func GetSeveritiesFormat added in v2.32.0

func GetSeveritiesFormat(severity string) (string, error)

func GetUniqueKey added in v2.40.0

func GetUniqueKey(vulnerableDependency, vulnerableVersion, xrayID string, fixVersionExist bool) string

GetUniqueKey returns a unique string key of format "vulnerableDependency:vulnerableVersion:xrayID:fixVersionExist"

func IsApplicableResult added in v2.41.6

func IsApplicableResult(result *sarif.Result) bool

func IsEmptyScanResponse added in v2.19.0

func IsEmptyScanResponse(results []services.ScanResponse) bool

func NewFailBuildError added in v2.7.0

func NewFailBuildError() error

func NewReport added in v2.41.5

func NewReport() (*sarif.Report, error)

func ParseAnalyzerManagerError added in v2.39.3

func ParseAnalyzerManagerError(scanner JasScanType, err error) error

func PrepareIacs added in v2.36.0

func PrepareIacs(iacs []*sarif.Run) []formats.SourceCodeRow

Prepare iacs for all non-table formats (without style or emoji)

func PrepareLicenses added in v2.12.2

func PrepareLicenses(licenses []services.License) ([]formats.LicenseRow, error)

func PrepareSast added in v2.41.5

func PrepareSast(sasts []*sarif.Run) []formats.SourceCodeRow

func PrepareSecrets added in v2.36.0

func PrepareSecrets(secrets []*sarif.Run) []formats.SourceCodeRow

Prepare secrets for all non-table formats (without style or emoji)

func PrepareViolations added in v2.12.2

func PrepareViolations(violations []services.Violation, extendedResults *ExtendedScanResults, multipleRoots, simplifiedOutput bool) ([]formats.VulnerabilityOrViolationRow, []formats.LicenseRow, []formats.OperationalRiskViolationRow, error)

Prepare violations for all non-table formats (without style or emoji)

func PrepareVulnerabilities added in v2.12.2

func PrepareVulnerabilities(vulnerabilities []services.Vulnerability, extendedResults *ExtendedScanResults, multipleRoots, simplifiedOutput bool) ([]formats.VulnerabilityOrViolationRow, error)

Prepare vulnerabilities for all non-table formats (without style or emoji)

func PrintIacTable added in v2.36.0

func PrintIacTable(iacs []*sarif.Run, entitledForIacScan bool) error

func PrintJson added in v2.1.0

func PrintJson(output interface{}) error

func PrintLicensesTable added in v2.1.0

func PrintLicensesTable(licenses []services.License, printExtended bool, scanType services.ScanType) error

PrintLicensesTable prints the licenses in a table. Set multipleRoots to true in case the given licenses array contains (or may contain) results of several projects or files (like in binary scan). In case multipleRoots is true, the field Component will show the root of each impact path, otherwise it will show the root's child. Set printExtended to true to print fields with 'extended' tag. If the scan argument is set to true, print the scan tables.

func PrintSastTable added in v2.41.5

func PrintSastTable(sast []*sarif.Run, entitledForSastScan bool) error

func PrintSecretsTable added in v2.36.0

func PrintSecretsTable(secrets []*sarif.Run, entitledForSecretsScan bool) error

func PrintViolationsTable

func PrintViolationsTable(violations []services.Violation, extendedResults *ExtendedScanResults, multipleRoots, printExtended bool, scanType services.ScanType) error

PrintViolationsTable prints the violations in 4 tables: security violations, license compliance violations, operational risk violations and ignore rule URLs. Set multipleRoots to true in case the given violations array contains (or may contain) results of several projects or files (like in binary scan). In case multipleRoots is true, the field Component will show the root of each impact path, otherwise it will show the root's child. In case one (or more) of the violations contains the field FailBuild set to true, CliError with exit code 3 will be returned. Set printExtended to true to print fields with 'extended' tag. If the scan argument is set to true, print the scan tables.

func PrintVulnerabilitiesTable

func PrintVulnerabilitiesTable(vulnerabilities []services.Vulnerability, extendedResults *ExtendedScanResults, multipleRoots, printExtended bool, scanType services.ScanType) error

PrintVulnerabilitiesTable prints the vulnerabilities in a table. Set multipleRoots to true in case the given vulnerabilities array contains (or may contain) results of several projects or files (like in binary scan). In case multipleRoots is true, the field Component will show the root of each impact path, otherwise it will show the root's child. Set printExtended to true to print fields with 'extended' tag. If the scan argument is set to true, print the scan tables.

func ReadScanRunsFromFile added in v2.41.5

func ReadScanRunsFromFile(fileName string) (sarifRuns []*sarif.Run, err error)

func SetAnalyzerManagerEnvVariables added in v2.33.0

func SetAnalyzerManagerEnvVariables(serverDetails *config.ServerDetails) error

func SetLocationFileName added in v2.41.5

func SetLocationFileName(location *sarif.Location, fileName string)

func SetLocationSnippet added in v2.41.5

func SetLocationSnippet(location *sarif.Location, snippet string)

func SplitComponentId added in v2.27.0

func SplitComponentId(componentId string) (string, string, string)

SplitComponentId splits a Xray component ID to the component name, version and package type. In case componentId doesn't contain a version, the returned version will be an empty string. In case componentId's format is invalid, it will be returned as the component name and empty strings will be returned instead of the version and the package type. Examples:

  1. componentId: "gav://antparent:ant:1.6.5" Returned values: Component name: "antparent:ant" Component version: "1.6.5" Package type: "Maven"
  2. componentId: "generic://sha256:244fd47e07d1004f0aed9c156aa09083c82bf8944eceb67c946ff7430510a77b/foo.jar" Returned values: Component name: "foo.jar" Component version: "" Package type: "Generic"
  3. componentId: "invalid-comp-id" Returned values: Component name: "invalid-comp-id" Component version: "" Package type: ""

func SplitScanResults added in v2.29.2

func SplitScanResults(results []services.ScanResponse) ([]services.Violation, []services.Vulnerability, []services.License)

Splits scan responses into aggregated lists of violations, vulnerabilities and licenses.

Types

type AnalyzerManager added in v2.33.0

type AnalyzerManager struct {
	AnalyzerManagerFullPath string
	MultiScanId             string
}

func (*AnalyzerManager) Exec added in v2.33.0

func (am *AnalyzerManager) Exec(configFile, scanCommand, workingDir string, serverDetails *config.ServerDetails) (err error)

func (*AnalyzerManager) ExecWithOutputFile added in v2.44.0

func (am *AnalyzerManager) ExecWithOutputFile(configFile, scanCommand, workingDir, outputFile string, serverDetails *config.ServerDetails) (err error)

type ApplicabilityStatus added in v2.41.5

type ApplicabilityStatus string
const (
	Applicable                ApplicabilityStatus = "Applicable"
	NotApplicable             ApplicabilityStatus = "Not Applicable"
	ApplicabilityUndetermined ApplicabilityStatus = "Undetermined"
	NotScanned                ApplicabilityStatus = ""
)

func (ApplicabilityStatus) String added in v2.43.2

func (as ApplicabilityStatus) String() string

type AuditBasicParams added in v2.41.5

type AuditBasicParams struct {
	// contains filtered or unexported fields
}

func (*AuditBasicParams) AppendDependenciesForApplicabilityScan added in v2.43.0

func (abp *AuditBasicParams) AppendDependenciesForApplicabilityScan(directDependencies []string) *AuditBasicParams

func (*AuditBasicParams) Args added in v2.41.5

func (abp *AuditBasicParams) Args() []string

func (*AuditBasicParams) DepsRepo added in v2.41.5

func (abp *AuditBasicParams) DepsRepo() string

func (*AuditBasicParams) DirectDependencies added in v2.41.5

func (abp *AuditBasicParams) DirectDependencies() []string

func (*AuditBasicParams) ExcludeTestDependencies added in v2.41.5

func (abp *AuditBasicParams) ExcludeTestDependencies() bool

func (*AuditBasicParams) IgnoreConfigFile added in v2.41.5

func (abp *AuditBasicParams) IgnoreConfigFile() bool

func (*AuditBasicParams) InsecureTls added in v2.41.5

func (abp *AuditBasicParams) InsecureTls() bool

func (*AuditBasicParams) OutputFormat added in v2.41.5

func (abp *AuditBasicParams) OutputFormat() OutputFormat

func (*AuditBasicParams) PipRequirementsFile added in v2.41.5

func (abp *AuditBasicParams) PipRequirementsFile() string

func (*AuditBasicParams) Progress added in v2.41.5

func (abp *AuditBasicParams) Progress() ioUtils.ProgressMgr

func (*AuditBasicParams) ServerDetails added in v2.41.5

func (abp *AuditBasicParams) ServerDetails() (*config.ServerDetails, error)

func (*AuditBasicParams) SetDepsRepo added in v2.41.5

func (abp *AuditBasicParams) SetDepsRepo(depsRepo string) *AuditBasicParams

func (*AuditBasicParams) SetExcludeTestDependencies added in v2.41.5

func (abp *AuditBasicParams) SetExcludeTestDependencies(excludeTestDependencies bool) *AuditBasicParams

func (*AuditBasicParams) SetIgnoreConfigFile added in v2.41.5

func (abp *AuditBasicParams) SetIgnoreConfigFile(ignoreConfigFile bool) *AuditBasicParams

func (*AuditBasicParams) SetInsecureTls added in v2.41.5

func (abp *AuditBasicParams) SetInsecureTls(insecureTls bool) *AuditBasicParams

func (*AuditBasicParams) SetNpmScope added in v2.41.5

func (abp *AuditBasicParams) SetNpmScope(depType string) *AuditBasicParams

func (*AuditBasicParams) SetOutputFormat added in v2.41.5

func (abp *AuditBasicParams) SetOutputFormat(format OutputFormat) *AuditBasicParams

func (*AuditBasicParams) SetPipRequirementsFile added in v2.41.5

func (abp *AuditBasicParams) SetPipRequirementsFile(requirementsFile string) *AuditBasicParams

func (*AuditBasicParams) SetProgress added in v2.41.5

func (abp *AuditBasicParams) SetProgress(progress ioUtils.ProgressMgr)

func (*AuditBasicParams) SetServerDetails added in v2.41.5

func (abp *AuditBasicParams) SetServerDetails(serverDetails *config.ServerDetails) *AuditBasicParams

func (*AuditBasicParams) SetTechnologies added in v2.41.5

func (abp *AuditBasicParams) SetTechnologies(technologies []string) *AuditBasicParams

func (*AuditBasicParams) SetUseWrapper added in v2.41.5

func (abp *AuditBasicParams) SetUseWrapper(useWrapper bool) *AuditBasicParams

func (*AuditBasicParams) Technologies added in v2.41.5

func (abp *AuditBasicParams) Technologies() []string

func (*AuditBasicParams) UseWrapper added in v2.41.5

func (abp *AuditBasicParams) UseWrapper() bool

type AuditNpmParams added in v2.44.0

type AuditNpmParams struct {
	AuditParams
	// contains filtered or unexported fields
}

func (AuditNpmParams) NpmIgnoreNodeModules added in v2.44.0

func (anp AuditNpmParams) NpmIgnoreNodeModules() bool

func (AuditNpmParams) NpmOverwritePackageLock added in v2.44.0

func (anp AuditNpmParams) NpmOverwritePackageLock() bool

func (AuditNpmParams) SetNpmIgnoreNodeModules added in v2.44.0

func (anp AuditNpmParams) SetNpmIgnoreNodeModules(ignoreNpmNodeModules bool) AuditNpmParams

func (AuditNpmParams) SetNpmOverwritePackageLock added in v2.44.0

func (anp AuditNpmParams) SetNpmOverwritePackageLock(overwritePackageLock bool) AuditNpmParams

type AuditParams added in v2.44.0

type AuditParams interface {
	DirectDependencies() []string
	AppendDependenciesForApplicabilityScan(directDependencies []string) *AuditBasicParams
	ServerDetails() (*config.ServerDetails, error)
	SetServerDetails(serverDetails *config.ServerDetails) *AuditBasicParams
	PipRequirementsFile() string
	SetPipRequirementsFile(requirementsFile string) *AuditBasicParams
	ExcludeTestDependencies() bool
	SetExcludeTestDependencies(excludeTestDependencies bool) *AuditBasicParams
	UseWrapper() bool
	SetUseWrapper(useWrapper bool) *AuditBasicParams
	InsecureTls() bool
	SetInsecureTls(insecureTls bool) *AuditBasicParams
	Technologies() []string
	SetTechnologies(technologies []string) *AuditBasicParams
	Progress() ioUtils.ProgressMgr
	SetProgress(progress ioUtils.ProgressMgr)
	Args() []string
	SetNpmScope(depType string) *AuditBasicParams
	OutputFormat() OutputFormat
	DepsRepo() string
	SetDepsRepo(depsRepo string) *AuditBasicParams
	IgnoreConfigFile() bool
	SetIgnoreConfigFile(ignoreConfigFile bool) *AuditBasicParams
}

type ExtendedScanResults added in v2.33.0

type ExtendedScanResults struct {
	XrayResults         []services.ScanResponse
	XrayVersion         string
	ScannedTechnologies []coreutils.Technology

	ApplicabilityScanResults []*sarif.Run
	SecretsScanResults       []*sarif.Run
	IacScanResults           []*sarif.Run
	SastScanResults          []*sarif.Run
	EntitledForJas           bool
}

type JasScanType added in v2.41.5

type JasScanType string
const (
	Applicability JasScanType = "Applicability"
	Secrets       JasScanType = "Secrets"
	IaC           JasScanType = "IaC"
	Sast          JasScanType = "Sast"
)

func (JasScanType) FormattedError added in v2.41.5

func (jst JasScanType) FormattedError(err error) error

func (JasScanType) String added in v2.43.2

func (jst JasScanType) String() string

type OutputFormat added in v2.7.0

type OutputFormat string
const (
	// OutputFormat values
	Table      OutputFormat = "table"
	Json       OutputFormat = "json"
	SimpleJson OutputFormat = "simple-json"
	Sarif      OutputFormat = "sarif"

	BaseDocumentationURL = "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/"
)

type ResultsWriter added in v2.44.0

type ResultsWriter struct {
	// contains filtered or unexported fields
}

func NewResultsWriter added in v2.44.0

func NewResultsWriter(extendedScanResults *ExtendedScanResults) *ResultsWriter

func (*ResultsWriter) PrintScanResults added in v2.44.0

func (rw *ResultsWriter) PrintScanResults() error

PrintScanResults prints the scan results in the specified format. Note that errors are printed only with SimpleJson format.

func (*ResultsWriter) SetExtraMessages added in v2.44.0

func (rw *ResultsWriter) SetExtraMessages(messages []string) *ResultsWriter

func (*ResultsWriter) SetIncludeLicenses added in v2.44.0

func (rw *ResultsWriter) SetIncludeLicenses(licenses bool) *ResultsWriter

func (*ResultsWriter) SetIncludeVulnerabilities added in v2.44.0

func (rw *ResultsWriter) SetIncludeVulnerabilities(includeVulnerabilities bool) *ResultsWriter

func (*ResultsWriter) SetIsMultipleRootProject added in v2.44.0

func (rw *ResultsWriter) SetIsMultipleRootProject(isMultipleRootProject bool) *ResultsWriter

func (*ResultsWriter) SetOutputFormat added in v2.44.0

func (rw *ResultsWriter) SetOutputFormat(format OutputFormat) *ResultsWriter

func (*ResultsWriter) SetPrintExtendedTable added in v2.44.0

func (rw *ResultsWriter) SetPrintExtendedTable(extendedTable bool) *ResultsWriter

func (*ResultsWriter) SetScanType added in v2.44.0

func (rw *ResultsWriter) SetScanType(scanType services.ScanType) *ResultsWriter

func (*ResultsWriter) SetSimpleJsonError added in v2.44.0

func (rw *ResultsWriter) SetSimpleJsonError(jsonErrors []formats.SimpleJsonError) *ResultsWriter

type SarifLevel added in v2.41.5

type SarifLevel string

type TableSeverity added in v2.43.2

type TableSeverity struct {
	formats.SeverityDetails
	// contains filtered or unexported fields
}

func GetSeverity added in v2.32.0

func GetSeverity(severityTitle string, applicable ApplicabilityStatus) *TableSeverity

func (*TableSeverity) Emoji added in v2.43.2

func (s *TableSeverity) Emoji() string

func (*TableSeverity) NumValue added in v2.43.2

func (s *TableSeverity) NumValue() int

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL