Skip to content

Commit e36219a

Browse files
committed
Initial commit
1 parent 8113cd0 commit e36219a

8 files changed

+266
-0
lines changed

.github/workflows/test.yml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: Test
2+
3+
on:
4+
push:
5+
branches: [ master ]
6+
pull_request:
7+
branches: [ master ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
go: [ '1.18', '1.19', '1.20', '1.21', '1.22' ]
15+
16+
steps:
17+
- name: Checkout code
18+
uses: actions/checkout@v2
19+
20+
- name: Run tests
21+
run: GO_IMAGE="golang:${{ matrix.go }}-alpine" docker compose run --rm test

cover.html

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
2+
<!DOCTYPE html>
3+
<html>
4+
<head>
5+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
6+
<title>secretenv: Go Coverage Report</title>
7+
<style>
8+
body {
9+
background: black;
10+
color: rgb(80, 80, 80);
11+
}
12+
body, pre, #legend span {
13+
font-family: Menlo, monospace;
14+
font-weight: bold;
15+
}
16+
#topbar {
17+
background: black;
18+
position: fixed;
19+
top: 0; left: 0; right: 0;
20+
height: 42px;
21+
border-bottom: 1px solid rgb(80, 80, 80);
22+
}
23+
#content {
24+
margin-top: 50px;
25+
}
26+
#nav, #legend {
27+
float: left;
28+
margin-left: 10px;
29+
}
30+
#legend {
31+
margin-top: 12px;
32+
}
33+
#nav {
34+
margin-top: 10px;
35+
}
36+
#legend span {
37+
margin: 0 5px;
38+
}
39+
.cov0 { color: rgb(192, 0, 0) }
40+
.cov1 { color: rgb(128, 128, 128) }
41+
.cov2 { color: rgb(116, 140, 131) }
42+
.cov3 { color: rgb(104, 152, 134) }
43+
.cov4 { color: rgb(92, 164, 137) }
44+
.cov5 { color: rgb(80, 176, 140) }
45+
.cov6 { color: rgb(68, 188, 143) }
46+
.cov7 { color: rgb(56, 200, 146) }
47+
.cov8 { color: rgb(44, 212, 149) }
48+
.cov9 { color: rgb(32, 224, 152) }
49+
.cov10 { color: rgb(20, 236, 155) }
50+
51+
</style>
52+
</head>
53+
<body>
54+
<div id="topbar">
55+
<div id="nav">
56+
<select id="files">
57+
58+
<option value="file0">github.com/ndthuan/secretenv/secretenv.go (100.0%)</option>
59+
60+
</select>
61+
</div>
62+
<div id="legend">
63+
<span>not tracked</span>
64+
65+
<span class="cov0">not covered</span>
66+
<span class="cov8">covered</span>
67+
68+
</div>
69+
</div>
70+
<div id="content">
71+
72+
<pre class="file" id="file0" style="display: none">package secretenv
73+
74+
import (
75+
"io"
76+
"os"
77+
"strings"
78+
)
79+
80+
// Get first checks if the key suffixed with "_FILE" exists.
81+
// If it does, it reads the content of the file and returns it.
82+
// Otherwise, it returns the environment value of the key.
83+
func Get(key string) string <span class="cov8" title="1">{
84+
if key == "" </span><span class="cov8" title="1">{
85+
return ""
86+
}</span>
87+
88+
<span class="cov8" title="1">fileKey := key + "_FILE"
89+
90+
if value, ok := os.LookupEnv(fileKey); ok </span><span class="cov8" title="1">{
91+
file, err := os.Open(value)
92+
if err == nil </span><span class="cov8" title="1">{
93+
defer file.Close()
94+
95+
data, err := io.ReadAll(file)
96+
if err == nil </span><span class="cov8" title="1">{
97+
return strings.TrimSpace(string(data))
98+
}</span>
99+
}
100+
}
101+
102+
<span class="cov8" title="1">return os.Getenv(key)</span>
103+
}
104+
</pre>
105+
106+
</div>
107+
</body>
108+
<script>
109+
(function() {
110+
var files = document.getElementById('files');
111+
var visible;
112+
files.addEventListener('change', onChange, false);
113+
function select(part) {
114+
if (visible)
115+
visible.style.display = 'none';
116+
visible = document.getElementById(part);
117+
if (!visible)
118+
return;
119+
files.value = part;
120+
visible.style.display = 'block';
121+
location.hash = part;
122+
}
123+
function onChange() {
124+
select(files.value);
125+
window.scrollTo(0, 0);
126+
}
127+
if (location.hash != "") {
128+
select(location.hash.substr(1));
129+
}
130+
if (!visible) {
131+
select("file0");
132+
}
133+
})();
134+
</script>
135+
</html>

docker-compose.yml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
services:
2+
test:
3+
image: $GO_IMAGE
4+
build:
5+
context: .
6+
dockerfile: Dockerfile
7+
ports:
8+
- "8080:8080"
9+
volumes:
10+
- .:/app
11+
command: go test -coverprofile cover.out -v ./...
12+
secrets:
13+
- test_secret
14+
environment:
15+
- MY_SECRET_FILE=/run/secrets/test_secret
16+
- MY_ENV_VAR=8IZoM8dq2FDkP+yhhGGzFhn+ZaxbHvQDxQNjXoxr
17+
working_dir: /app
18+
19+
secrets:
20+
test_secret:
21+
file: testsecret

go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/ndthuan/secretenv
2+
3+
go 1.18

runtests.sh

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/bash
2+
goVers="1.18 1.19 1.20 1.21 1.22"
3+
for ver in $goVers; do
4+
echo "Running tests for Go $ver"
5+
6+
GO_IMAGE="golang:$ver-alpine" docker compose run --rm test
7+
done

secretenv.go

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package secretenv
2+
3+
import (
4+
"io"
5+
"os"
6+
"strings"
7+
)
8+
9+
// Get first checks if the key suffixed with "_FILE" exists.
10+
// If it does, it reads the content of the file and returns it.
11+
// Otherwise, it returns the environment value of the key.
12+
func Get(key string) string {
13+
if key == "" {
14+
return ""
15+
}
16+
17+
fileKey := key + "_FILE"
18+
19+
if value, ok := os.LookupEnv(fileKey); ok {
20+
file, err := os.Open(value)
21+
if err == nil {
22+
defer file.Close()
23+
24+
data, err := io.ReadAll(file)
25+
if err == nil {
26+
return strings.TrimSpace(string(data))
27+
}
28+
}
29+
}
30+
31+
return os.Getenv(key)
32+
}

secretenv_test.go

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package secretenv_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/ndthuan/secretenv"
7+
)
8+
9+
func TestGet(t *testing.T) {
10+
type args struct {
11+
key string
12+
}
13+
tests := []struct {
14+
name string
15+
args args
16+
want string
17+
}{
18+
{
19+
name: "empty key",
20+
args: args{key: ""},
21+
want: "",
22+
},
23+
{
24+
name: "secret file found, return its content",
25+
args: args{key: "MY_SECRET"},
26+
want: "dxgkscDpDOz0qRadSU/OMrk0nV3DwwzFJmOVA+ei",
27+
},
28+
{
29+
name: "secret file not found, fallback to its corresponding ENV",
30+
args: args{key: "MY_ENV_VAR"},
31+
want: "8IZoM8dq2FDkP+yhhGGzFhn+ZaxbHvQDxQNjXoxr",
32+
},
33+
{
34+
name: "neither secret file nor ENV var found, return empty string",
35+
args: args{key: "NOT_FOUND"},
36+
want: "",
37+
},
38+
}
39+
for _, tt := range tests {
40+
t.Run(tt.name, func(t *testing.T) {
41+
if got := secretenv.Get(tt.args.key); got != tt.want {
42+
t.Errorf("Get() = %v, want %v", got, tt.want)
43+
}
44+
})
45+
}
46+
}

testsecret

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dxgkscDpDOz0qRadSU/OMrk0nV3DwwzFJmOVA+ei

0 commit comments

Comments
 (0)