From c27c40c534c046bce3f9e1d677a3223e14d84816 Mon Sep 17 00:00:00 2001
From: Romain Dartigues <romain.dartigues.ext@orange.com>
Date: Tue, 14 May 2024 13:15:26 +0200
Subject: [PATCH 1/4] upgrade go and dependencies

---
 go.mod                                        |  6 +--
 go.sum                                        |  4 +-
 .../prometheus/procfs/Makefile.common         |  2 +-
 .../github.com/prometheus/procfs/buddyinfo.go |  4 +-
 vendor/github.com/prometheus/procfs/mdstat.go | 42 ++++++++++++-------
 .../prometheus/procfs/mountstats.go           |  4 +-
 vendor/github.com/prometheus/procfs/proc.go   |  2 +-
 .../prometheus/procfs/proc_smaps.go           |  2 +-
 vendor/modules.txt                            |  2 +-
 9 files changed, 38 insertions(+), 30 deletions(-)

diff --git a/go.mod b/go.mod
index dc5ea957..73b49111 100644
--- a/go.mod
+++ b/go.mod
@@ -1,8 +1,6 @@
 module github.com/orange-cloudfoundry/boshupdate_exporter
 
-go 1.22
-
-toolchain go1.22.0
+go 1.22.3
 
 require (
 	github.com/Masterminds/semver v1.5.0
@@ -35,7 +33,7 @@ require (
 	github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
 	github.com/pivotal-cf/paraphernalia v0.0.0-20180203224945-a64ae2051c20 // indirect
 	github.com/prometheus/client_model v0.6.1 // indirect
-	github.com/prometheus/procfs v0.14.0 // indirect
+	github.com/prometheus/procfs v0.15.0 // indirect
 	github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
 	golang.org/x/crypto v0.23.0 // indirect
 	golang.org/x/net v0.25.0 // indirect
diff --git a/go.sum b/go.sum
index b9bf5d58..a2c0a2f4 100644
--- a/go.sum
+++ b/go.sum
@@ -78,8 +78,8 @@ github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p
 github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
 github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE=
 github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
-github.com/prometheus/procfs v0.14.0 h1:Lw4VdGGoKEZilJsayHf0B+9YgLGREba2C6xr+Fdfq6s=
-github.com/prometheus/procfs v0.14.0/go.mod h1:XL+Iwz8k8ZabyZfMFHPiilCniixqQarAy5Mu67pHlNQ=
+github.com/prometheus/procfs v0.15.0 h1:A82kmvXJq2jTu5YUhSGNlYoxh85zLnKgPz4bMZgI5Ek=
+github.com/prometheus/procfs v0.15.0/go.mod h1:Y0RJ/Y5g5wJpkTisOtqwDSo4HwhGmLB4VQSw2sQJLHk=
 github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
 github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
 github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
diff --git a/vendor/github.com/prometheus/procfs/Makefile.common b/vendor/github.com/prometheus/procfs/Makefile.common
index 0acfb9d8..0e9ace29 100644
--- a/vendor/github.com/prometheus/procfs/Makefile.common
+++ b/vendor/github.com/prometheus/procfs/Makefile.common
@@ -55,7 +55,7 @@ ifneq ($(shell command -v gotestsum 2> /dev/null),)
 endif
 endif
 
-PROMU_VERSION ?= 0.15.0
+PROMU_VERSION ?= 0.17.0
 PROMU_URL     := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz
 
 SKIP_GOLANGCI_LINT :=
diff --git a/vendor/github.com/prometheus/procfs/buddyinfo.go b/vendor/github.com/prometheus/procfs/buddyinfo.go
index eb88d78a..83807500 100644
--- a/vendor/github.com/prometheus/procfs/buddyinfo.go
+++ b/vendor/github.com/prometheus/procfs/buddyinfo.go
@@ -58,8 +58,8 @@ func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) {
 			return nil, fmt.Errorf("%w: Invalid number of fields, found: %v", ErrFileParse, parts)
 		}
 
-		node := strings.TrimRight(parts[1], ",")
-		zone := strings.TrimRight(parts[3], ",")
+		node := strings.TrimSuffix(parts[1], ",")
+		zone := strings.TrimSuffix(parts[3], ",")
 		arraySize := len(parts[4:])
 
 		if bucketCount == -1 {
diff --git a/vendor/github.com/prometheus/procfs/mdstat.go b/vendor/github.com/prometheus/procfs/mdstat.go
index dd2b8988..67a9d2b4 100644
--- a/vendor/github.com/prometheus/procfs/mdstat.go
+++ b/vendor/github.com/prometheus/procfs/mdstat.go
@@ -23,7 +23,7 @@ import (
 
 var (
 	statusLineRE         = regexp.MustCompile(`(\d+) blocks .*\[(\d+)/(\d+)\] \[([U_]+)\]`)
-	recoveryLineBlocksRE = regexp.MustCompile(`\((\d+)/\d+\)`)
+	recoveryLineBlocksRE = regexp.MustCompile(`\((\d+/\d+)\)`)
 	recoveryLinePctRE    = regexp.MustCompile(`= (.+)%`)
 	recoveryLineFinishRE = regexp.MustCompile(`finish=(.+)min`)
 	recoveryLineSpeedRE  = regexp.MustCompile(`speed=(.+)[A-Z]`)
@@ -50,6 +50,8 @@ type MDStat struct {
 	BlocksTotal int64
 	// Number of blocks on the device that are in sync.
 	BlocksSynced int64
+	// Number of blocks on the device that need to be synced.
+	BlocksToBeSynced int64
 	// progress percentage of current sync
 	BlocksSyncedPct float64
 	// estimated finishing time for current sync (in minutes)
@@ -115,7 +117,8 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
 
 		// If device is syncing at the moment, get the number of currently
 		// synced bytes, otherwise that number equals the size of the device.
-		syncedBlocks := size
+		blocksSynced := size
+		blocksToBeSynced := size
 		speed := float64(0)
 		finish := float64(0)
 		pct := float64(0)
@@ -136,9 +139,9 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
 			// Handle case when resync=PENDING or resync=DELAYED.
 			if strings.Contains(lines[syncLineIdx], "PENDING") ||
 				strings.Contains(lines[syncLineIdx], "DELAYED") {
-				syncedBlocks = 0
+				blocksSynced = 0
 			} else {
-				syncedBlocks, pct, finish, speed, err = evalRecoveryLine(lines[syncLineIdx])
+				blocksSynced, blocksToBeSynced, pct, finish, speed, err = evalRecoveryLine(lines[syncLineIdx])
 				if err != nil {
 					return nil, fmt.Errorf("%w: Cannot parse sync line in md device: %q: %w", ErrFileParse, mdName, err)
 				}
@@ -154,7 +157,8 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
 			DisksSpare:             spare,
 			DisksTotal:             total,
 			BlocksTotal:            size,
-			BlocksSynced:           syncedBlocks,
+			BlocksSynced:           blocksSynced,
+			BlocksToBeSynced:       blocksToBeSynced,
 			BlocksSyncedPct:        pct,
 			BlocksSyncedFinishTime: finish,
 			BlocksSyncedSpeed:      speed,
@@ -206,48 +210,54 @@ func evalStatusLine(deviceLine, statusLine string) (active, total, down, size in
 	return active, total, down, size, nil
 }
 
-func evalRecoveryLine(recoveryLine string) (syncedBlocks int64, pct float64, finish float64, speed float64, err error) {
+func evalRecoveryLine(recoveryLine string) (blocksSynced int64, blocksToBeSynced int64, pct float64, finish float64, speed float64, err error) {
 	matches := recoveryLineBlocksRE.FindStringSubmatch(recoveryLine)
 	if len(matches) != 2 {
-		return 0, 0, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine %s: %w", ErrFileParse, recoveryLine, err)
+		return 0, 0, 0, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine blocks %s: %w", ErrFileParse, recoveryLine, err)
 	}
 
-	syncedBlocks, err = strconv.ParseInt(matches[1], 10, 64)
+	blocks := strings.Split(matches[1], "/")
+	blocksSynced, err = strconv.ParseInt(blocks[0], 10, 64)
 	if err != nil {
-		return 0, 0, 0, 0, fmt.Errorf("%w: Unexpected parsing of recoveryLine %q: %w", ErrFileParse, recoveryLine, err)
+		return 0, 0, 0, 0, 0, fmt.Errorf("%w: Unable to parse recovery blocks synced %q: %w", ErrFileParse, matches[1], err)
+	}
+
+	blocksToBeSynced, err = strconv.ParseInt(blocks[1], 10, 64)
+	if err != nil {
+		return blocksSynced, 0, 0, 0, 0, fmt.Errorf("%w: Unable to parse recovery to be synced blocks %q: %w", ErrFileParse, matches[2], err)
 	}
 
 	// Get percentage complete
 	matches = recoveryLinePctRE.FindStringSubmatch(recoveryLine)
 	if len(matches) != 2 {
-		return syncedBlocks, 0, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine matching percentage %s", ErrFileParse, recoveryLine)
+		return blocksSynced, blocksToBeSynced, 0, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine matching percentage %s", ErrFileParse, recoveryLine)
 	}
 	pct, err = strconv.ParseFloat(strings.TrimSpace(matches[1]), 64)
 	if err != nil {
-		return syncedBlocks, 0, 0, 0, fmt.Errorf("%w: Error parsing float from recoveryLine %q", ErrFileParse, recoveryLine)
+		return blocksSynced, blocksToBeSynced, 0, 0, 0, fmt.Errorf("%w: Error parsing float from recoveryLine %q", ErrFileParse, recoveryLine)
 	}
 
 	// Get time expected left to complete
 	matches = recoveryLineFinishRE.FindStringSubmatch(recoveryLine)
 	if len(matches) != 2 {
-		return syncedBlocks, pct, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine matching est. finish time: %s", ErrFileParse, recoveryLine)
+		return blocksSynced, blocksToBeSynced, pct, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine matching est. finish time: %s", ErrFileParse, recoveryLine)
 	}
 	finish, err = strconv.ParseFloat(matches[1], 64)
 	if err != nil {
-		return syncedBlocks, pct, 0, 0, fmt.Errorf("%w: Unable to parse float from recoveryLine: %q", ErrFileParse, recoveryLine)
+		return blocksSynced, blocksToBeSynced, pct, 0, 0, fmt.Errorf("%w: Unable to parse float from recoveryLine: %q", ErrFileParse, recoveryLine)
 	}
 
 	// Get recovery speed
 	matches = recoveryLineSpeedRE.FindStringSubmatch(recoveryLine)
 	if len(matches) != 2 {
-		return syncedBlocks, pct, finish, 0, fmt.Errorf("%w: Unexpected recoveryLine value: %s", ErrFileParse, recoveryLine)
+		return blocksSynced, blocksToBeSynced, pct, finish, 0, fmt.Errorf("%w: Unexpected recoveryLine value: %s", ErrFileParse, recoveryLine)
 	}
 	speed, err = strconv.ParseFloat(matches[1], 64)
 	if err != nil {
-		return syncedBlocks, pct, finish, 0, fmt.Errorf("%w: Error parsing float from recoveryLine: %q: %w", ErrFileParse, recoveryLine, err)
+		return blocksSynced, blocksToBeSynced, pct, finish, 0, fmt.Errorf("%w: Error parsing float from recoveryLine: %q: %w", ErrFileParse, recoveryLine, err)
 	}
 
-	return syncedBlocks, pct, finish, speed, nil
+	return blocksSynced, blocksToBeSynced, pct, finish, speed, nil
 }
 
 func evalComponentDevices(deviceFields []string) []string {
diff --git a/vendor/github.com/prometheus/procfs/mountstats.go b/vendor/github.com/prometheus/procfs/mountstats.go
index 2f54e77c..75a3b6c8 100644
--- a/vendor/github.com/prometheus/procfs/mountstats.go
+++ b/vendor/github.com/prometheus/procfs/mountstats.go
@@ -88,7 +88,7 @@ type MountStatsNFS struct {
 	// Statistics broken down by filesystem operation.
 	Operations []NFSOperationStats
 	// Statistics about the NFS RPC transport.
-	Transport NFSTransportStats
+	Transport []NFSTransportStats
 }
 
 // mountStats implements MountStats.
@@ -432,7 +432,7 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e
 				return nil, err
 			}
 
-			stats.Transport = *tstats
+			stats.Transport = append(stats.Transport, *tstats)
 		}
 
 		// When encountering "per-operation statistics", we must break this
diff --git a/vendor/github.com/prometheus/procfs/proc.go b/vendor/github.com/prometheus/procfs/proc.go
index 0e8c4fa0..14279636 100644
--- a/vendor/github.com/prometheus/procfs/proc.go
+++ b/vendor/github.com/prometheus/procfs/proc.go
@@ -137,7 +137,7 @@ func (p Proc) CmdLine() ([]string, error) {
 		return []string{}, nil
 	}
 
-	return strings.Split(string(bytes.TrimRight(data, string("\x00"))), string(byte(0))), nil
+	return strings.Split(string(bytes.TrimRight(data, "\x00")), "\x00"), nil
 }
 
 // Wchan returns the wchan (wait channel) of a process.
diff --git a/vendor/github.com/prometheus/procfs/proc_smaps.go b/vendor/github.com/prometheus/procfs/proc_smaps.go
index ad8785a4..09060e82 100644
--- a/vendor/github.com/prometheus/procfs/proc_smaps.go
+++ b/vendor/github.com/prometheus/procfs/proc_smaps.go
@@ -127,7 +127,7 @@ func (s *ProcSMapsRollup) parseLine(line string) error {
 	}
 
 	v := strings.TrimSpace(kv[1])
-	v = strings.TrimRight(v, " kB")
+	v = strings.TrimSuffix(v, " kB")
 
 	vKBytes, err := strconv.ParseUint(v, 10, 64)
 	if err != nil {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 17721b93..544bb650 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -86,7 +86,7 @@ github.com/prometheus/common/expfmt
 github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg
 github.com/prometheus/common/model
 github.com/prometheus/common/version
-# github.com/prometheus/procfs v0.14.0
+# github.com/prometheus/procfs v0.15.0
 ## explicit; go 1.21
 github.com/prometheus/procfs
 github.com/prometheus/procfs/internal/fs

From 7552c7fc099111ac0722e8df5b9cae820f00e6f7 Mon Sep 17 00:00:00 2001
From: Romain Dartigues <romain.dartigues.ext@orange.com>
Date: Tue, 14 May 2024 13:48:31 +0200
Subject: [PATCH 2/4] CI: add CodeQL Analysis workflow

---
 .github/workflows/codeql-analysis.yml | 67 +++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)
 create mode 100644 .github/workflows/codeql-analysis.yml

diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 00000000..f6f3a70f
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,67 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL"
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    # The branches below must be a subset of the branches above
+    branches: [ master ]
+  schedule:
+    - cron: '29 22 * * 0'
+
+jobs:
+  analyze:
+    name: Analyze
+    runs-on: ubuntu-latest
+
+    strategy:
+      fail-fast: false
+      matrix:
+        language: [ 'go' ]
+        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
+        # Learn more:
+        # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
+
+    steps:
+    - name: Checkout repository
+      uses: actions/checkout@v4
+
+    # Initializes the CodeQL tools for scanning.
+    - name: Initialize CodeQL
+      uses: github/codeql-action/init@v3
+      with:
+        languages: ${{ matrix.language }}
+        # If you wish to specify custom queries, you can do so here or in a config file.
+        # By default, queries listed here will override any specified in a config file.
+        # Prefix the list here with "+" to use these queries and those in the config file.
+        # queries: ./path/to/local/query, your-org/your-repo/queries@main
+
+    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
+    # If this step fails, then you should remove it and run the build manually (see below)
+    - name: Autobuild
+      uses: github/codeql-action/autobuild@v3
+
+    # ℹī¸ Command-line programs to run using the OS shell.
+    # 📚 https://git.io/JvXDl
+
+    # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines
+    #    and modify them (or add more) to build your code if your project
+    #    uses a compiled language
+
+    #- run: |
+    #   make bootstrap
+    #   make release
+
+    - name: Perform CodeQL Analysis
+      uses: github/codeql-action/analyze@v3

From bed4be312b023434c09be9de20d622217435f81e Mon Sep 17 00:00:00 2001
From: Romain Dartigues <romain.dartigues.ext@orange.com>
Date: Tue, 14 May 2024 13:49:33 +0200
Subject: [PATCH 3/4] CI: fix invalid file format introduced by 561bf7c

---
 .github/dependabot.yml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index f29d9d69..aad71833 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -10,6 +10,6 @@ updates:
     schedule:
       interval: "daily"
   - package-ecosystem: "github-actions"
-  directory: "/"
-  schedule:
-    interval: "daily"
+    directory: "/"
+    schedule:
+      interval: "daily"

From e69e0b484d2484cb90e2c664923a9ec6d75e1a75 Mon Sep 17 00:00:00 2001
From: Romain Dartigues <romain.dartigues.ext@orange.com>
Date: Tue, 14 May 2024 13:49:53 +0200
Subject: [PATCH 4/4] typos

---
 README.md            | 58 ++++++++++++++++++++++----------------------
 boshupdate/bosh.go   |  2 +-
 boshupdate/models.go |  2 +-
 3 files changed, 31 insertions(+), 31 deletions(-)

diff --git a/README.md b/README.md
index 9c4e68ce..07cde674 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 A [Prometheus][prometheus] exporter that identifies out of date [BOSH][bosh] deployments.
 
-It queries [Github][github] and fetches available releases of canonical [BOSH][bosh] manifests
+It queries [GitHub][github] and fetches available releases of canonical [BOSH][bosh] manifests
 such as [cf-deployment][cf-deployment], then conciliates with actual running deployments
 fetched from [BOSH][bosh]  director.
 
@@ -29,16 +29,16 @@ $ docker run -p 9362:9362 orangeopensource/boshupdate-exporter <flags>
 
 ### BOSH
 
-This exporter can be deployed using the [Githubexporter BOSH Release][githubexporter-boshrelease].
+This exporter can be deployed using the BOSH Release: https://github.com/orange-cloudfoundry/boshupdate-boshrelease.
 
 ## Usage
 
-### Github Token
+### GitHub Token
 
-In order to connect to the [Github API][github_api] a `token` must be provided.
-The `token` can be created by following the [Github HowTo][github-create-token]
+In order to connect to the [GitHub API][github_api] a `token` must be provided.
+The `token` can be created by following the [GitHub HowTo][github-create-token]
 
-### Bosh deployment prerequites
+### Bosh deployment prerequisites
 
 The exporter identifies the version of a running deployment by extracting the `manifest_version`.
 
@@ -71,10 +71,10 @@ bosh:
   excludes: list[regexp]  # list of bosh deployment to exclude from scrap
 
 github:
-  token: <string>                          # your github token here
-  update_interval: 4h                      # interval between two github updates
+  token: <string>                          # your GitHub token here
+  update_interval: 4h                      # interval between two GitHub updates
   manifest_releases: map[string, manifest] # list of canonical manifests to monitor
-  generic_releases:  map[string, generic]  # list of generic github release to monitor
+  generic_releases:  map[string, generic]  # list of generic GitHub release to monitor
 ```
 
 
@@ -84,8 +84,8 @@ github:
 <name>:
     types: *release-types*
     format: *release-formatter*
-    owner: <string>        # github project's owner or organization
-    repo: <string>         # github project's name
+    owner: <string>        # GitHub project's owner or organization
+    repo: <string>         # GitHub project's name
     manifest: <string>     # remote path to main BOSH manifest
     ops: list[string]      # list of remote ops-file paths to apply to main manifest
     vars: list[string]     # list of remote vars-file paths to apply to main manifest
@@ -98,8 +98,8 @@ github:
 <name>:
     types: *release-types*
     format: *release-formatter*
-    owner: <string>     # github project's owner or organization
-    repo: <string>      # github project's name
+    owner: <string>     # GitHub project's owner or organization
+    repo: <string>      # GitHub project's name
 ```
 
 * *release-types*
@@ -109,10 +109,10 @@ github:
 list[string]
 
 # String must be one or more of the following values:
-# - release:       Github release which is neither in 'draft' nor 'pre' state
-# - pre_release:   Github release in 'pre' state
-# - draft_release: Github release in 'draft' state
-# - tag:           Github tag
+# - release:       GitHub release which is neither in 'draft' nor 'pre' state
+# - pre_release:   GitHub release in 'pre' state
+# - draft_release: GitHub release in 'draft' state
+# - tag:           GitHub tag
 ```
 
 * *format*
@@ -131,17 +131,17 @@ format:
 
 ### Flags
 
-| Flag / Environment Variable                                          | Required | Default         | Description                                                                                                                                                                                                                           |
-| ---------------------------                                          | -------- | -------         | -----------                                                                                                                                                                                                                           |
-| `config`<br />`BOSHUPDATE_EXPORTER_CONFIG`                           | No       | `config.yml`    | Path to configuration file                                                                                                                                                                                                            |
-| `metrics.namespace`<br />`BOSHUPDATE_EXPORTER_METRICS_NAMESPACE`     | No       | `boshupdate`    | Metrics Namespace                                                                                                                                                                                                                     |
-| `metrics.environment`<br />`BOSHUPDATE_EXPORTER_METRICS_ENVIRONMENT` | Yes      |                 | `environment` label to be attached to metrics                                                                                                                                                                                         |
-| `web.listen-address`<br />`BOSHUPDATE_EXPORTER_WEB_LISTEN_ADDRESS`   | No       | `:9362`         | Address to listen on for web interface and telemetry                                                                                                                                                                                  |
-| `web.telemetry-path`<br />`BOSHUPDATE_EXPORTER_WEB_TELEMETRY_PATH`   | No       | `/metrics`      | Path under which to expose Prometheus metrics                                                                                                                                                                                         |
-| `web.auth.username`<br />`BOSHUPDATE_EXPORTER_WEB_AUTH_USERNAME`     | No       |                 | Username for web interface basic auth                                                                                                                                                                                                 |
-| `web.auth.password`<br />`BOSHUPDATE_EXPORTER_WEB_AUTH_PASSWORD`     | No       |                 | Password for web interface basic auth                                                                                                                                                                                                 |
-| `web.tls.cert_file`<br />`BOSHUPDATE_EXPORTER_WEB_TLS_CERTFILE`      | No       |                 | Path to a file that contains the TLS certificate (PEM format). If the certificate is signed by a certificate authority, the file should be the concatenation of the server's certificate, any intermediates, and the CA's certificate |
-| `web.tls.key_file`<br />`BOSHUPDATE_EXPORTER_WEB_TLS_KEYFILE`        | No       |                 | Path to a file that contains the TLS private key (PEM format)                                                                                                                                                                         |
+| Flag / Environment Variable                                          | Required | Default      | Description                                                                                                                                                                                                                           |
+|----------------------------------------------------------------------|----------|--------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `config`<br />`BOSHUPDATE_EXPORTER_CONFIG`                           | No       | `config.yml` | Path to configuration file                                                                                                                                                                                                            |
+| `metrics.namespace`<br />`BOSHUPDATE_EXPORTER_METRICS_NAMESPACE`     | No       | `boshupdate` | Metrics Namespace                                                                                                                                                                                                                     |
+| `metrics.environment`<br />`BOSHUPDATE_EXPORTER_METRICS_ENVIRONMENT` | Yes      |              | `environment` label to be attached to metrics                                                                                                                                                                                         |
+| `web.listen-address`<br />`BOSHUPDATE_EXPORTER_WEB_LISTEN_ADDRESS`   | No       | `:9362`      | Address to listen on for web interface and telemetry                                                                                                                                                                                  |
+| `web.telemetry-path`<br />`BOSHUPDATE_EXPORTER_WEB_TELEMETRY_PATH`   | No       | `/metrics`   | Path under which to expose Prometheus metrics                                                                                                                                                                                         |
+| `web.auth.username`<br />`BOSHUPDATE_EXPORTER_WEB_AUTH_USERNAME`     | No       |              | Username for web interface basic auth                                                                                                                                                                                                 |
+| `web.auth.password`<br />`BOSHUPDATE_EXPORTER_WEB_AUTH_PASSWORD`     | No       |              | Password for web interface basic auth                                                                                                                                                                                                 |
+| `web.tls.cert_file`<br />`BOSHUPDATE_EXPORTER_WEB_TLS_CERTFILE`      | No       |              | Path to a file that contains the TLS certificate (PEM format). If the certificate is signed by a certificate authority, the file should be the concatenation of the server's certificate, any intermediates, and the CA's certificate |
+| `web.tls.key_file`<br />`BOSHUPDATE_EXPORTER_WEB_TLS_KEYFILE`        | No       |              | Path to a file that contains the TLS private key (PEM format)                                                                                                                                                                         |
 
 
 ### Metrics
@@ -152,7 +152,7 @@ The exporter returns the following  metrics:
 | Metric                                             | Description                                                                                   | Labels                                                                                                                                 |
 |----------------------------------------------------|-----------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------|
 | *metrics.namespace*_manifest_release               | Seconds from epoch since canonical manifest version if out-of-date, 0 means up-to-date        | `environment`, `name`, `version`, `owner`, `repo`                                                                                      |
-| *metrics.namespace*_manifest_bosh_release_info     | Information about recommended bosh releases used by last available canonical manifest release | `environment`, `manifest_name`, `onwer`, `repo`, `boshrelease_name`, `boshrelease_version`, `boshrelease_url`                          |
+| *metrics.namespace*_manifest_bosh_release_info     | Information about recommended bosh releases used by last available canonical manifest release | `environment`, `manifest_name`, `owner`, `repo`, `boshrelease_name`, `boshrelease_version`, `boshrelease_url`                          |
 | *metrics.namespace*_generic_release                | Seconds from epoch since repository version is out-of-date, 0 means up-to-date                | `environment`, `name`, `version`, `owner`, `repo`                                                                                      |
 | *metrics.namespace*_deployment_status              | Seconds from epoch since deployment is out-of-date, 0 means up-to-date                        | `environment`, `name`, `current`, `latest`                                                                                             |
 | *metrics.namespace*_deployment_bosh_release_status | Seconds from epoch since bosh release is out-of-date, 0 means up-to-date                      | `environment`, `manifest_name`, `manifest_current`, `manifest_latest`, `boshrelease_name`, `boshrelease_current`, `boshrelease_latest` |
diff --git a/boshupdate/bosh.go b/boshupdate/bosh.go
index 988985f2..aceaef21 100644
--- a/boshupdate/bosh.go
+++ b/boshupdate/bosh.go
@@ -128,7 +128,7 @@ func NewDirector(config BoshConfig) (director.Director, error) {
 		uaaURL := infos.Auth.Options["url"]
 		uaaURLStr, ok := uaaURL.(string)
 		if !ok {
-			return nil, fmt.Errorf("Expected UAA URL '%s' to be a string", uaaURL)
+			return nil, fmt.Errorf("expected UAA URL '%s' to be a string", uaaURL)
 		}
 		uaaCli, err := buildUAA(uaaURLStr, config, log)
 		if err != nil {
diff --git a/boshupdate/models.go b/boshupdate/models.go
index 5b8cdd43..493a1013 100644
--- a/boshupdate/models.go
+++ b/boshupdate/models.go
@@ -16,7 +16,7 @@ func (s *Formatter) Format(ref string) string {
 	return re.ReplaceAllString(ref, s.Replace)
 }
 
-// Match -
+// DoesMatch -
 func (s *Formatter) DoesMatch(ref string) bool {
 	re := regexp.MustCompile(s.Match)
 	return re.MatchString(ref)