Compare commits
6 Commits
v2023.3.29
...
v2023.3.31
Author | SHA1 | Date | |
---|---|---|---|
dff95c7af9 | |||
e5b6c5e949 | |||
9c69dc7ec8 | |||
4e6b450338 | |||
351f22e216 | |||
854a6ae41b |
69
Jenkinsfile
vendored
Normal file
69
Jenkinsfile
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
@Library('cadoles') _
|
||||||
|
|
||||||
|
pipeline {
|
||||||
|
agent {
|
||||||
|
dockerfile {
|
||||||
|
label 'docker'
|
||||||
|
filename 'Dockerfile'
|
||||||
|
dir 'misc/jenkins'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stages {
|
||||||
|
stage('Run unit tests') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
withCredentials([
|
||||||
|
usernamePassword([
|
||||||
|
credentialsId: 'forge-jenkins',
|
||||||
|
usernameVariable: 'GIT_USERNAME',
|
||||||
|
passwordVariable: 'GIT_PASSWORD'
|
||||||
|
])
|
||||||
|
]) {
|
||||||
|
sh '''
|
||||||
|
git config --global credential.https://forge.cadoles.com.username "$GIT_USERNAME"
|
||||||
|
git config --global credential.https://forge.cadoles.com.helper '!f() { test "$1" = get && echo "password=$GIT_PASSWORD"; }; f'
|
||||||
|
export GOPRIVATE=forge.cadoles.com/arcad/edge
|
||||||
|
make test
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Release') {
|
||||||
|
when {
|
||||||
|
anyOf {
|
||||||
|
branch 'master'
|
||||||
|
branch 'develop'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
withCredentials([
|
||||||
|
usernamePassword([
|
||||||
|
credentialsId: 'forge-jenkins',
|
||||||
|
usernameVariable: 'GITEA_RELEASE_USERNAME',
|
||||||
|
passwordVariable: 'GITEA_RELEASE_PASSWORD'
|
||||||
|
])
|
||||||
|
]) {
|
||||||
|
sh 'make gitea-release'
|
||||||
|
}
|
||||||
|
def currentVersion = sh(returnStdout: true, script: 'make full-version').trim()
|
||||||
|
build(
|
||||||
|
job: "../emissary-firmware/${env.GIT_BRANCH}",
|
||||||
|
parameters: [
|
||||||
|
[$class: 'StringParameterValue', name: 'emissaryVersion', value: currentVersion]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
cleanWs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
Makefile
5
Makefile
@ -150,4 +150,7 @@ AGENT_ID ?= 1
|
|||||||
|
|
||||||
load-sample-specs:
|
load-sample-specs:
|
||||||
cat misc/spec-samples/app.emissary.cadoles.com.json | ./bin/server api agent spec update -a $(AGENT_ID) --no-patch --spec-data - --spec-name app.emissary.cadoles.com
|
cat misc/spec-samples/app.emissary.cadoles.com.json | ./bin/server api agent spec update -a $(AGENT_ID) --no-patch --spec-data - --spec-name app.emissary.cadoles.com
|
||||||
cat misc/spec-samples/proxy.emissary.cadoles.com.json | ./bin/server api agent spec update -a $(AGENT_ID) --no-patch --spec-data - --spec-name proxy.emissary.cadoles.com
|
cat misc/spec-samples/proxy.emissary.cadoles.com.json | ./bin/server api agent spec update -a $(AGENT_ID) --no-patch --spec-data - --spec-name proxy.emissary.cadoles.com
|
||||||
|
|
||||||
|
full-version:
|
||||||
|
@echo $(FULL_VERSION)
|
@ -16,8 +16,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type serverEntry struct {
|
type serverEntry struct {
|
||||||
SpecHash uint64
|
AppDefHash uint64
|
||||||
Server *Server
|
Server *Server
|
||||||
}
|
}
|
||||||
|
|
||||||
type Controller struct {
|
type Controller struct {
|
||||||
@ -124,7 +124,20 @@ func (c *Controller) updateAppRepository(ctx context.Context, specs *spec.Spec)
|
|||||||
func (c *Controller) updateApp(ctx context.Context, specs *spec.Spec, appKey string) (err error) {
|
func (c *Controller) updateApp(ctx context.Context, specs *spec.Spec, appKey string) (err error) {
|
||||||
appEntry := specs.Apps[appKey]
|
appEntry := specs.Apps[appKey]
|
||||||
|
|
||||||
newAppSpecHash, err := hashstructure.Hash(appEntry, hashstructure.FormatV2, nil)
|
var auth *spec.Auth
|
||||||
|
if specs.Config != nil {
|
||||||
|
auth = specs.Config.Auth
|
||||||
|
}
|
||||||
|
|
||||||
|
appDef := struct {
|
||||||
|
App spec.AppEntry
|
||||||
|
Auth *spec.Auth
|
||||||
|
}{
|
||||||
|
App: appEntry,
|
||||||
|
Auth: auth,
|
||||||
|
}
|
||||||
|
|
||||||
|
newAppDefHash, err := hashstructure.Hash(appDef, hashstructure.FormatV2, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
@ -163,20 +176,20 @@ func (c *Controller) updateApp(ctx context.Context, specs *spec.Spec, appKey str
|
|||||||
}
|
}
|
||||||
|
|
||||||
server = &serverEntry{
|
server = &serverEntry{
|
||||||
Server: NewServer(bundle, auth, options...),
|
Server: NewServer(bundle, auth, options...),
|
||||||
SpecHash: 0,
|
AppDefHash: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
c.servers[appKey] = server
|
c.servers[appKey] = server
|
||||||
}
|
}
|
||||||
|
|
||||||
specChanged := newAppSpecHash != server.SpecHash
|
defChanged := newAppDefHash != server.AppDefHash
|
||||||
|
|
||||||
if server.Server.Running() && !specChanged {
|
if server.Server.Running() && !defChanged {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if specChanged && server.SpecHash != 0 {
|
if defChanged && server.AppDefHash != 0 {
|
||||||
logger.Info(
|
logger.Info(
|
||||||
ctx, "restarting app",
|
ctx, "restarting app",
|
||||||
logger.F("address", appEntry.Address),
|
logger.F("address", appEntry.Address),
|
||||||
@ -194,7 +207,7 @@ func (c *Controller) updateApp(ctx context.Context, specs *spec.Spec, appKey str
|
|||||||
return errors.Wrap(err, "could not start app")
|
return errors.Wrap(err, "could not start app")
|
||||||
}
|
}
|
||||||
|
|
||||||
server.SpecHash = newAppSpecHash
|
server.AppDefHash = newAppDefHash
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,13 @@ package app
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec"
|
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec"
|
||||||
appSpec "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec"
|
appSpec "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec"
|
||||||
|
"forge.cadoles.com/Cadoles/emissary/internal/proxy/wildcard"
|
||||||
edgeHTTP "forge.cadoles.com/arcad/edge/pkg/http"
|
edgeHTTP "forge.cadoles.com/arcad/edge/pkg/http"
|
||||||
authHTTP "forge.cadoles.com/arcad/edge/pkg/module/auth/http"
|
authHTTP "forge.cadoles.com/arcad/edge/pkg/module/auth/http"
|
||||||
"gitlab.com/wpetit/goweb/logger"
|
"gitlab.com/wpetit/goweb/logger"
|
||||||
@ -109,7 +111,7 @@ func (s *Server) Stop() error {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
if err := s.server.Close(); err != nil {
|
if err := s.server.Close(); err != nil {
|
||||||
panic(errors.WithStack(err))
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -140,6 +142,10 @@ func (s *Server) configureAuth(router chi.Router, auth *spec.Auth) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.auth.Local.CookieDomain != "" {
|
||||||
|
router.Use(invalidCookieDomainRedirect(s.auth.Local.CookieDomain))
|
||||||
|
}
|
||||||
|
|
||||||
router.Handle("/auth/*", authHTTP.NewLocalHandler(
|
router.Handle("/auth/*", authHTTP.NewLocalHandler(
|
||||||
jwa.HS256, key,
|
jwa.HS256, key,
|
||||||
authHTTP.WithRoutePrefix("/auth"),
|
authHTTP.WithRoutePrefix("/auth"),
|
||||||
@ -158,3 +164,33 @@ func NewServer(bundle bundle.Bundle, auth *appSpec.Auth, handlerOptions ...edgeH
|
|||||||
handlerOptions: handlerOptions,
|
handlerOptions: handlerOptions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func invalidCookieDomainRedirect(cookieDomain string) func(http.Handler) http.Handler {
|
||||||
|
domain := strings.TrimPrefix(cookieDomain, ".")
|
||||||
|
hostPattern := "*" + domain
|
||||||
|
|
||||||
|
return func(h http.Handler) http.Handler {
|
||||||
|
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
hostParts := strings.SplitN(r.Host, ":", 2)
|
||||||
|
|
||||||
|
if !wildcard.Match(hostParts[0], hostPattern) {
|
||||||
|
url := r.URL
|
||||||
|
|
||||||
|
newHost := domain
|
||||||
|
if len(hostParts) > 1 {
|
||||||
|
newHost += ":" + hostParts[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
url.Host = newHost
|
||||||
|
|
||||||
|
http.Redirect(w, r, url.String(), http.StatusTemporaryRedirect)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.HandlerFunc(fn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -18,7 +18,7 @@ func GenerateToken(key jwk.Key, thumbprint string) (string, error) {
|
|||||||
return "", errors.WithStack(err)
|
return "", errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now().UTC()
|
||||||
|
|
||||||
if err := token.Set(jwt.NotBeforeKey, now); err != nil {
|
if err := token.Set(jwt.NotBeforeKey, now); err != nil {
|
||||||
return "", errors.WithStack(err)
|
return "", errors.WithStack(err)
|
||||||
|
2
internal/auth/thirdparty/jwt.go
vendored
2
internal/auth/thirdparty/jwt.go
vendored
@ -42,7 +42,7 @@ func GenerateToken(ctx context.Context, key jwk.Key, issuer, subject string, rol
|
|||||||
return "", errors.WithStack(err)
|
return "", errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now().UTC()
|
||||||
|
|
||||||
if err := token.Set(jwt.NotBeforeKey, now); err != nil {
|
if err := token.Set(jwt.NotBeforeKey, now); err != nil {
|
||||||
return "", errors.WithStack(err)
|
return "", errors.WithStack(err)
|
||||||
|
@ -15,6 +15,6 @@ type DatabaseConfig struct {
|
|||||||
func NewDefaultDatabaseConfig() DatabaseConfig {
|
func NewDefaultDatabaseConfig() DatabaseConfig {
|
||||||
return DatabaseConfig{
|
return DatabaseConfig{
|
||||||
Driver: "sqlite",
|
Driver: "sqlite",
|
||||||
DSN: "sqlite://emissary.sqlite",
|
DSN: "sqlite://emissary.sqlite?_fk=true&_journal=WAL",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,11 @@ func (r *AgentRepository) GetSpecs(ctx context.Context, agentID datastore.AgentI
|
|||||||
return nil, errors.WithStack(err)
|
return nil, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer rows.Close()
|
defer func() {
|
||||||
|
if err := rows.Close(); err != nil {
|
||||||
|
logger.Error(ctx, "could not close rows", logger.E(errors.WithStack(err)))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
spec := &datastore.Spec{}
|
spec := &datastore.Spec{}
|
||||||
@ -61,6 +65,10 @@ func (r *AgentRepository) GetSpecs(ctx context.Context, agentID datastore.AgentI
|
|||||||
specs = append(specs, spec)
|
specs = append(specs, spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
return specs, nil
|
return specs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,7 +184,11 @@ func (r *AgentRepository) Query(ctx context.Context, opts ...datastore.AgentQuer
|
|||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer rows.Close()
|
defer func() {
|
||||||
|
if err := rows.Close(); err != nil {
|
||||||
|
logger.Error(ctx, "could not close rows", logger.E(errors.WithStack(err)))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
agent := &datastore.Agent{}
|
agent := &datastore.Agent{}
|
||||||
@ -192,6 +204,10 @@ func (r *AgentRepository) Query(ctx context.Context, opts ...datastore.AgentQuer
|
|||||||
agents = append(agents, agent)
|
agents = append(agents, agent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
row := tx.QueryRowContext(ctx, `SELECT count(id) FROM agents `+filters, args...)
|
row := tx.QueryRowContext(ctx, `SELECT count(id) FROM agents `+filters, args...)
|
||||||
if err := row.Scan(&count); err != nil {
|
if err := row.Scan(&count); err != nil {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
|
24
misc/jenkins/Dockerfile
Normal file
24
misc/jenkins/Dockerfile
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
FROM reg.cadoles.com/proxy_cache/library/ubuntu:22.04
|
||||||
|
|
||||||
|
ARG HTTP_PROXY=
|
||||||
|
ARG HTTPS_PROXY=
|
||||||
|
ARG http_proxy=
|
||||||
|
ARG https_proxy=
|
||||||
|
ARG GO_VERSION=1.19.2
|
||||||
|
|
||||||
|
# Install dev environment dependencies
|
||||||
|
RUN export DEBIAN_FRONTEND=noninteractive &&\
|
||||||
|
apt-get update -y &&\
|
||||||
|
apt-get install -y --no-install-recommends curl ca-certificates build-essential wget unzip tar git jq
|
||||||
|
|
||||||
|
# Install Go
|
||||||
|
RUN mkdir -p /tmp \
|
||||||
|
&& wget -O /tmp/go${GO_VERSION}.linux-amd64.tar.gz https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz \
|
||||||
|
&& rm -rf /usr/local/go \
|
||||||
|
&& mkdir -p /usr/local \
|
||||||
|
&& tar -C /usr/local -xzf /tmp/go${GO_VERSION}.linux-amd64.tar.gz
|
||||||
|
|
||||||
|
ENV PATH="${PATH}:/usr/local/go/bin"
|
||||||
|
|
||||||
|
# Add LetsEncrypt certificates
|
||||||
|
RUN curl -k https://forge.cadoles.com/Cadoles/Jenkins/raw/branch/master/resources/com/cadoles/common/add-letsencrypt-ca.sh | bash
|
@ -9,7 +9,7 @@ server:
|
|||||||
port: 3000
|
port: 3000
|
||||||
database:
|
database:
|
||||||
driver: sqlite
|
driver: sqlite
|
||||||
dsn: sqlite:///var/lib/emissary/data.sqlite
|
dsn: sqlite:///var/lib/emissary/data.sqlite?_fk=true&_journal=WAL
|
||||||
cors:
|
cors:
|
||||||
allowedOrigins: []
|
allowedOrigins: []
|
||||||
allowCredentials: true
|
allowCredentials: true
|
||||||
|
Reference in New Issue
Block a user