1
0
mirror of https://github.com/NginxProxyManager/nginx-proxy-manager.git synced 2025-04-20 19:47:46 +03:00

CI stack for Authentik with ldap

This commit is contained in:
Jamie Curnow 2024-11-03 13:17:24 +10:00
parent a277a5d167
commit 6e820a36ac
No known key found for this signature in database
GPG Key ID: FFBB624C43388E9E
35 changed files with 116 additions and 172 deletions

9
Jenkinsfile vendored
View File

@ -188,6 +188,11 @@ pipeline {
sh 'docker logs $(docker-compose ps --all -q pdns) > debug/postgres/docker_pdns.log 2>&1' sh 'docker logs $(docker-compose ps --all -q pdns) > debug/postgres/docker_pdns.log 2>&1'
sh 'docker logs $(docker-compose ps --all -q pdns-db) > debug/postgres/docker_pdns-db.log 2>&1' sh 'docker logs $(docker-compose ps --all -q pdns-db) > debug/postgres/docker_pdns-db.log 2>&1'
sh 'docker logs $(docker-compose ps --all -q dnsrouter) > debug/postgres/docker_dnsrouter.log 2>&1' sh 'docker logs $(docker-compose ps --all -q dnsrouter) > debug/postgres/docker_dnsrouter.log 2>&1'
sh 'docker logs $(docker-compose ps --all -q db-postgres) > debug/postgres/docker_db.log 2>&1'
sh 'docker logs $(docker-compose ps --all -q authentik) > debug/postgres/docker_authentik.log 2>&1'
sh 'docker logs $(docker-compose ps --all -q authentik-redis) > debug/postgres/docker_authentik-redis.log 2>&1'
sh 'docker logs $(docker-compose ps --all -q authentik-ldap) > debug/postgres/docker_authentik-ldap.log 2>&1'
junit 'test/results/junit/*' junit 'test/results/junit/*'
sh 'docker-compose down --remove-orphans --volumes -t 30 || true' sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
} }
@ -248,16 +253,16 @@ pipeline {
printResult() printResult()
} }
failure { failure {
archiveArtifacts(artifacts: 'debug/**/*', allowEmptyArchive: true)
dir(path: 'test') { dir(path: 'test') {
archiveArtifacts allowEmptyArchive: true, artifacts: 'results/**/*', excludes: '**/*.xml' archiveArtifacts allowEmptyArchive: true, artifacts: 'results/**/*', excludes: '**/*.xml'
} }
archiveArtifacts(artifacts: 'debug/*', allowEmptyArchive: true)
} }
unstable { unstable {
archiveArtifacts(artifacts: 'debug/**/*', allowEmptyArchive: true)
dir(path: 'test') { dir(path: 'test') {
archiveArtifacts allowEmptyArchive: true, artifacts: 'results/**/*', excludes: '**/*.xml' archiveArtifacts allowEmptyArchive: true, artifacts: 'results/**/*', excludes: '**/*.xml'
} }
archiveArtifacts(artifacts: 'debug/*', allowEmptyArchive: true)
} }
} }
} }

View File

@ -18,4 +18,4 @@ threshold:
# package: 30 # package: 30
# (optional; default 0) # (optional; default 0)
# The minimum total coverage project should have # The minimum total coverage project should have
total: 34 total: 33

View File

@ -24,7 +24,7 @@
}, },
"type": { "type": {
"type": "string", "type": "string",
"pattern": "^password$" "pattern": "^(local|ldap|oidc)$"
} }
} }
} }

View File

@ -53,7 +53,7 @@
}, },
"type": { "type": {
"type": "string", "type": "string",
"pattern": "^password$" "pattern": "^(local|ldap|oidc)$"
} }
} }
}, },

View File

@ -125,14 +125,12 @@ INSERT INTO `user` (
`created_at`, `created_at`,
`updated_at`, `updated_at`,
`name`, `name`,
`nickname`,
`email`, `email`,
`is_system` `is_system`
) VALUES ( ) VALUES (
ROUND(UNIX_TIMESTAMP(CURTIME(4)) * 1000), ROUND(UNIX_TIMESTAMP(CURTIME(4)) * 1000),
ROUND(UNIX_TIMESTAMP(CURTIME(4)) * 1000), ROUND(UNIX_TIMESTAMP(CURTIME(4)) * 1000),
"System", "System",
"System",
"system@localhost", "system@localhost",
TRUE TRUE
); );

View File

@ -125,14 +125,12 @@ INSERT INTO "user" (
"created_at", "created_at",
"updated_at", "updated_at",
"name", "name",
"nickname",
"email", "email",
"is_system" "is_system"
) VALUES ( ) VALUES (
EXTRACT(EPOCH FROM TIMESTAMP '2011-05-17 10:40:28.876944') * 1000, EXTRACT(EPOCH FROM TIMESTAMP '2011-05-17 10:40:28.876944') * 1000,
EXTRACT(EPOCH FROM TIMESTAMP '2011-05-17 10:40:28.876944') * 1000, EXTRACT(EPOCH FROM TIMESTAMP '2011-05-17 10:40:28.876944') * 1000,
'System', 'System',
'System',
'system@localhost', 'system@localhost',
TRUE TRUE
); );

View File

@ -124,14 +124,12 @@ INSERT INTO `user` (
created_at, created_at,
updated_at, updated_at,
name, name,
nickname,
email, email,
is_system is_system
) VALUES ( ) VALUES (
unixepoch() * 1000, unixepoch() * 1000,
unixepoch() * 1000, unixepoch() * 1000,
"System", "System",
"System",
"system@localhost", "system@localhost",
1 1
); );

View File

@ -97,13 +97,14 @@ func (s *testsuite) TestSave() {
defer goleak.VerifyNone(s.T(), goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener")) defer goleak.VerifyNone(s.T(), goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener"))
s.mock.ExpectBegin() s.mock.ExpectBegin()
s.mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "auth" ("created_at","updated_at","is_deleted","user_id","type","secret") VALUES ($1,$2,$3,$4,$5,$6) RETURNING "id"`)). s.mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "auth" ("created_at","updated_at","is_deleted","user_id","type","identity","secret") VALUES ($1,$2,$3,$4,$5,$6,$7) RETURNING "id"`)).
WithArgs( WithArgs(
sqlmock.AnyArg(), sqlmock.AnyArg(),
sqlmock.AnyArg(), sqlmock.AnyArg(),
0, 0,
100, 100,
TypeLocal, TypeLocal,
"",
"abc123", "abc123",
). ).
WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow("11")) WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow("11"))

View File

@ -39,7 +39,6 @@ func (m *Model) LoadByID(id int) error {
// Save will save this model to the DB // Save will save this model to the DB
func (m *Model) Save() error { func (m *Model) Save() error {
db := database.GetDB() db := database.GetDB()
// todo: touch? not sure that save does this or not?
result := db.Save(m) result := db.Save(m)
return result.Error return result.Error
} }

View File

@ -84,7 +84,6 @@ func (s *testsuite) SetupTest() {
).AddRow( ).AddRow(
11, 11,
"Jane Doe", "Jane Doe",
"Jane",
"jane@example.com", "jane@example.com",
true, true,
false, false,
@ -183,7 +182,6 @@ func (s *testsuite) TestSave() {
sqlmock.AnyArg(), sqlmock.AnyArg(),
0, 0,
"John Doe", "John Doe",
"Jonny",
"sarah@example.com", "sarah@example.com",
false, false,
false, false,

8
docker/ci.env Normal file
View File

@ -0,0 +1,8 @@
AUTHENTIK_SECRET_KEY=gl8woZe8L6IIX8SC0c5Ocsj0xPkX5uJo5DVZCFl+L/QGbzuplfutYuua2ODNLEiDD3aFd9H2ylJmrke0
AUTHENTIK_REDIS__HOST=authentik-redis
AUTHENTIK_POSTGRESQL__HOST=db-postgres
AUTHENTIK_POSTGRESQL__USER=authentik
AUTHENTIK_POSTGRESQL__NAME=authentik
AUTHENTIK_POSTGRESQL__PASSWORD=07EKS5NLI6Tpv68tbdvrxfvj
AUTHENTIK_BOOTSTRAP_PASSWORD=admin
AUTHENTIK_BOOTSTRAP_EMAIL=admin@example.com

Binary file not shown.

View File

@ -12,15 +12,63 @@ services:
NPM_DB_SSLMODE: 'disable' NPM_DB_SSLMODE: 'disable'
depends_on: depends_on:
- db-postgres - db-postgres
- authentik
- authentik-worker
- authentik-ldap
db-postgres: db-postgres:
image: postgres:15 image: postgres:latest
environment: environment:
POSTGRES_USER: 'npm' POSTGRES_USER: 'npm'
POSTGRES_PASSWORD: 'npmpass' POSTGRES_PASSWORD: 'npmpass'
POSTGRES_DB: 'npm' POSTGRES_DB: 'npm'
volumes: volumes:
- psql_vol:/var/lib/postgresql/data - psql_vol:/var/lib/postgresql/data
- ./ci/postgres:/docker-entrypoint-initdb.d
authentik-redis:
image: 'redis:alpine'
command: --save 60 1 --loglevel warning
restart: unless-stopped
healthcheck:
test: ['CMD-SHELL', 'redis-cli ping | grep PONG']
start_period: 20s
interval: 30s
retries: 5
timeout: 3s
volumes:
- redis_vol:/data
authentik:
image: ghcr.io/goauthentik/server:2024.8.3
restart: unless-stopped
command: server
env_file:
- ci.env
depends_on:
- authentik-redis
- db-postgres
authentik-worker:
image: ghcr.io/goauthentik/server:2024.8.3
restart: unless-stopped
command: worker
env_file:
- ci.env
depends_on:
- authentik-redis
- db-postgres
authentik-ldap:
image: ghcr.io/goauthentik/ldap
environment:
AUTHENTIK_HOST: 'http://authentik:9000'
AUTHENTIK_INSECURE: 'true'
AUTHENTIK_TOKEN: '1N7z2r5PZrNBauuyDZSnlhU4gPSih7bkooIgqbvhzBbrA1MGYyDGZmBasJqU'
restart: unless-stopped
depends_on:
- authentik
volumes: volumes:
psql_vol: psql_vol:
redis_vol:

View File

@ -25,7 +25,6 @@ curl --request POST \
--header 'Content-Type: application/json' \ --header 'Content-Type: application/json' \
--data '{ --data '{
"name": "Bobby Tables", "name": "Bobby Tables",
"nickname": "Bobby",
"email": "you@example.com", "email": "you@example.com",
"roles": ["admin"], "roles": ["admin"],
"is_disabled": false, "is_disabled": false,

View File

@ -8,7 +8,6 @@ export interface AuthOptions {
export interface NewUser { export interface NewUser {
name: string; name: string;
nickname: string;
email: string; email: string;
isDisabled: boolean; isDisabled: boolean;
auth: AuthOptions; auth: AuthOptions;

View File

@ -14,7 +14,6 @@ export interface UserAuth {
export interface User { export interface User {
id: number; id: number;
name: string; name: string;
nickname: string;
email: string; email: string;
createdOn: number; createdOn: number;
updatedOn: number; updatedOn: number;

View File

@ -185,6 +185,9 @@
"error.email-already-exists": { "error.email-already-exists": {
"defaultMessage": "Es existiert bereits ein Benutzer mit dieser E-Mail-Adresse" "defaultMessage": "Es existiert bereits ein Benutzer mit dieser E-Mail-Adresse"
}, },
"error.invalid-auth-type": {
"defaultMessage": "Invalid authentication type"
},
"error.invalid-login-credentials": { "error.invalid-login-credentials": {
"defaultMessage": "Ungültige Login-Details" "defaultMessage": "Ungültige Login-Details"
}, },
@ -440,9 +443,6 @@
"user.name": { "user.name": {
"defaultMessage": "Name" "defaultMessage": "Name"
}, },
"user.nickname": {
"defaultMessage": "Benutzername"
},
"user.password": { "user.password": {
"defaultMessage": "Passwort" "defaultMessage": "Passwort"
}, },

View File

@ -461,6 +461,9 @@
"error.email-already-exists": { "error.email-already-exists": {
"defaultMessage": "A user already exists with this email address" "defaultMessage": "A user already exists with this email address"
}, },
"error.invalid-auth-type": {
"defaultMessage": "Invalid authentication type"
},
"error.invalid-login-credentials": { "error.invalid-login-credentials": {
"defaultMessage": "Invalid login credentials" "defaultMessage": "Invalid login credentials"
}, },
@ -722,9 +725,6 @@
"user.name": { "user.name": {
"defaultMessage": "Name" "defaultMessage": "Name"
}, },
"user.nickname": {
"defaultMessage": "Nickname"
},
"user.password": { "user.password": {
"defaultMessage": "Password" "defaultMessage": "Password"
}, },

View File

@ -185,6 +185,9 @@
"error.email-already-exists": { "error.email-already-exists": {
"defaultMessage": "کاربری از قبل با این آدرس ایمیل وجود دارد" "defaultMessage": "کاربری از قبل با این آدرس ایمیل وجود دارد"
}, },
"error.invalid-auth-type": {
"defaultMessage": "Invalid authentication type"
},
"error.invalid-login-credentials": { "error.invalid-login-credentials": {
"defaultMessage": "اعتبار ورود نامعتبر است" "defaultMessage": "اعتبار ورود نامعتبر است"
}, },
@ -443,9 +446,6 @@
"user.name": { "user.name": {
"defaultMessage": "نام" "defaultMessage": "نام"
}, },
"user.nickname": {
"defaultMessage": "کنیه"
},
"user.password": { "user.password": {
"defaultMessage": "کلمه عبور" "defaultMessage": "کلمه عبور"
}, },

View File

@ -5,19 +5,19 @@ import {
FormLabel, FormLabel,
Input, Input,
Modal, Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalCloseButton,
ModalBody, ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter, ModalFooter,
ModalHeader,
ModalOverlay,
Stack, Stack,
useToast, useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { Formik, Form, Field } from "formik"; import { Field, Form, Formik } from "formik";
import { PrettyButton } from "src/components"; import { PrettyButton } from "src/components";
import { useUser, useSetUser } from "src/hooks"; import { useSetUser, useUser } from "src/hooks";
import { intl } from "src/locale"; import { intl } from "src/locale";
import { validateEmail, validateString } from "src/modules/Validations"; import { validateEmail, validateString } from "src/modules/Validations";
@ -59,7 +59,6 @@ function ProfileModal({ isOpen, onClose }: ProfileModalProps) {
<Formik <Formik
initialValues={{ initialValues={{
name: user.data?.name, name: user.data?.name,
nickname: user.data?.nickname,
email: user.data?.email, email: user.data?.email,
}} }}
onSubmit={onSubmit}> onSubmit={onSubmit}>
@ -71,7 +70,7 @@ function ProfileModal({ isOpen, onClose }: ProfileModalProps) {
<ModalCloseButton /> <ModalCloseButton />
<ModalBody> <ModalBody>
<Stack spacing={4}> <Stack spacing={4}>
<Field name="name" validate={validateString(2, 100)}> <Field name="name" validate={validateString(2, 50)}>
{({ field, form }: any) => ( {({ field, form }: any) => (
<FormControl <FormControl
isRequired isRequired
@ -91,30 +90,6 @@ function ProfileModal({ isOpen, onClose }: ProfileModalProps) {
</FormControl> </FormControl>
)} )}
</Field> </Field>
<Field name="nickname" validate={validateString(2, 100)}>
{({ field, form }: any) => (
<FormControl
isRequired
isInvalid={
form.errors.nickname && form.touched.nickname
}>
<FormLabel htmlFor="nickname">
{intl.formatMessage({ id: "user.nickname" })}
</FormLabel>
<Input
{...field}
id="nickname"
defaultValue={values.nickname}
placeholder={intl.formatMessage({
id: "user.nickname",
})}
/>
<FormErrorMessage>
{form.errors.nickname}
</FormErrorMessage>
</FormControl>
)}
</Field>
<Field name="email" validate={validateEmail()}> <Field name="email" validate={validateEmail()}>
{({ field, form }: any) => ( {({ field, form }: any) => (
<FormControl <FormControl

View File

@ -35,7 +35,6 @@ import { validateEmail, validateString } from "src/modules/Validations";
interface Payload { interface Payload {
name: string; name: string;
nickname: string;
email: string; email: string;
password: string; password: string;
} }
@ -110,7 +109,6 @@ function UserCreateModal({ isOpen, onClose }: UserCreateModalProps) {
initialValues={ initialValues={
{ {
name: "", name: "",
nickname: "",
email: "", email: "",
password: "", password: "",
} as Payload } as Payload
@ -131,7 +129,7 @@ function UserCreateModal({ isOpen, onClose }: UserCreateModalProps) {
<TabPanels> <TabPanels>
<TabPanel> <TabPanel>
<Stack spacing={4}> <Stack spacing={4}>
<Field name="name" validate={validateString(2, 100)}> <Field name="name" validate={validateString(2, 50)}>
{({ field, form }: any) => ( {({ field, form }: any) => (
<FormControl <FormControl
isRequired isRequired
@ -152,31 +150,6 @@ function UserCreateModal({ isOpen, onClose }: UserCreateModalProps) {
</FormControl> </FormControl>
)} )}
</Field> </Field>
<Field
name="nickname"
validate={validateString(2, 100)}>
{({ field, form }: any) => (
<FormControl
isRequired
isInvalid={
form.errors.nickname && form.touched.nickname
}>
<FormLabel htmlFor="nickname">
{intl.formatMessage({ id: "user.nickname" })}
</FormLabel>
<Input
{...field}
id="nickname"
placeholder={intl.formatMessage({
id: "user.nickname",
})}
/>
<FormErrorMessage>
{form.errors.nickname}
</FormErrorMessage>
</FormControl>
)}
</Field>
<Field name="email" validate={validateEmail()}> <Field name="email" validate={validateEmail()}>
{({ field, form }: any) => ( {({ field, form }: any) => (
<FormControl <FormControl

View File

@ -8,28 +8,28 @@ import {
FormLabel, FormLabel,
Input, Input,
Modal, Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalCloseButton,
ModalBody, ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter, ModalFooter,
ModalHeader,
ModalOverlay,
Stack, Stack,
Tab, Tab,
Tabs,
TabList, TabList,
TabPanel, TabPanel,
TabPanels, TabPanels,
Tabs,
useToast, useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { Formik, Form, Field } from "formik"; import { Field, Form, Formik } from "formik";
import { import {
AdminPermissionSelector, AdminPermissionSelector,
PermissionSelector, PermissionSelector,
PrettyButton, PrettyButton,
} from "src/components"; } from "src/components";
import { useUser, useSetUser } from "src/hooks"; import { useSetUser, useUser } from "src/hooks";
import { intl } from "src/locale"; import { intl } from "src/locale";
import { validateEmail, validateString } from "src/modules/Validations"; import { validateEmail, validateString } from "src/modules/Validations";
@ -106,7 +106,6 @@ function UserEditModal({ userId, isOpen, onClose }: UserEditModalProps) {
initialValues={ initialValues={
{ {
name: data?.name, name: data?.name,
nickname: data?.nickname,
email: data?.email, email: data?.email,
isDisabled: data?.isDisabled, isDisabled: data?.isDisabled,
} as any } as any
@ -129,7 +128,7 @@ function UserEditModal({ userId, isOpen, onClose }: UserEditModalProps) {
<TabPanels> <TabPanels>
<TabPanel> <TabPanel>
<Stack spacing={4}> <Stack spacing={4}>
<Field name="name" validate={validateString(2, 100)}> <Field name="name" validate={validateString(2, 50)}>
{({ field, form }: any) => ( {({ field, form }: any) => (
<FormControl <FormControl
isRequired isRequired
@ -152,31 +151,6 @@ function UserEditModal({ userId, isOpen, onClose }: UserEditModalProps) {
</FormControl> </FormControl>
)} )}
</Field> </Field>
<Field
name="nickname"
validate={validateString(2, 100)}>
{({ field, form }: any) => (
<FormControl
isRequired
isInvalid={
form.errors.nickname && form.touched.nickname
}>
<FormLabel htmlFor="nickname">
{intl.formatMessage({ id: "user.nickname" })}
</FormLabel>
<Input
{...field}
id="nickname"
placeholder={intl.formatMessage({
id: "user.nickname",
})}
/>
<FormErrorMessage>
{form.errors.nickname}
</FormErrorMessage>
</FormControl>
)}
</Field>
<Field name="email" validate={validateEmail()}> <Field name="email" validate={validateEmail()}>
{({ field, form }: any) => ( {({ field, form }: any) => (
<FormControl <FormControl

View File

@ -1,10 +1,9 @@
import { useEffect, useMemo, useState } from "react"; import { useEffect, useMemo, useState } from "react";
import { FiDownload, FiEdit, FiRefreshCw, FiTrash2 } from "react-icons/fi"; import { FiDownload, FiEdit, FiRefreshCw, FiTrash2 } from "react-icons/fi";
import { useSortBy, useFilters, useTable, usePagination } from "react-table"; import { useFilters, usePagination, useSortBy, useTable } from "react-table";
import { import {
tableEvents,
ActionsFormatter, ActionsFormatter,
CertificateStatusFormatter, CertificateStatusFormatter,
CertificateTypeFormatter, CertificateTypeFormatter,
@ -12,6 +11,7 @@ import {
GravatarFormatter, GravatarFormatter,
IDFormatter, IDFormatter,
MonospaceFormatter, MonospaceFormatter,
tableEvents,
TableFilter, TableFilter,
TableLayout, TableLayout,
TablePagination, TablePagination,
@ -123,7 +123,7 @@ function Table({
}, },
]; ];
return [columns, data]; return [columns, data];
}, [data, onRenewal]); }, [data, onRenewal, onDelete]);
const tableInstance = useTable( const tableInstance = useTable(
{ {

View File

@ -25,7 +25,6 @@ import { validateEmail, validateString } from "src/modules/Validations";
interface Payload { interface Payload {
name: string; name: string;
nickname: string;
email: string; email: string;
password: string; password: string;
} }
@ -122,7 +121,6 @@ function Setup() {
initialValues={ initialValues={
{ {
name: "", name: "",
nickname: "",
email: "", email: "",
password: "", password: "",
} as Payload } as Payload
@ -131,7 +129,7 @@ function Setup() {
{({ isSubmitting }) => ( {({ isSubmitting }) => (
<Form> <Form>
<Stack spacing={4}> <Stack spacing={4}>
<Field name="name" validate={validateString(2, 100)}> <Field name="name" validate={validateString(2, 50)}>
{({ field, form }: any) => ( {({ field, form }: any) => (
<FormControl <FormControl
isRequired isRequired
@ -153,29 +151,6 @@ function Setup() {
</FormControl> </FormControl>
)} )}
</Field> </Field>
<Field name="nickname" validate={validateString(2, 100)}>
{({ field, form }: any) => (
<FormControl
isRequired
isInvalid={
form.errors.nickname && form.touched.nickname
}>
<FormLabel htmlFor="nickname">
{intl.formatMessage({ id: "user.nickname" })}
</FormLabel>
<Input
{...field}
id="nickname"
placeholder={intl.formatMessage({
id: "user.nickname",
})}
/>
<FormErrorMessage>
{form.errors.nickname}
</FormErrorMessage>
</FormControl>
)}
</Field>
<Field name="email" validate={validateEmail()}> <Field name="email" validate={validateEmail()}>
{({ field, form }: any) => ( {({ field, form }: any) => (
<FormControl <FormControl

View File

@ -71,6 +71,7 @@ printf "nameserver %s\noptions ndots:0" "${DNSROUTER_IP}" > "${LOCAL_RESOLVE}"
docker-compose up -d --remove-orphans stepca docker-compose up -d --remove-orphans stepca
docker-compose pull db-mysql || true # ok to fail docker-compose pull db-mysql || true # ok to fail
docker-compose pull db-postgres || true # ok to fail docker-compose pull db-postgres || true # ok to fail
docker-compose pull authentik authentik-redis authentik-ldap || true # ok to fail
docker-compose up -d --remove-orphans --pull=never fullstack docker-compose up -d --remove-orphans --pull=never fullstack
# wait for main container to be healthy # wait for main container to be healthy

View File

@ -1,4 +1,4 @@
/// <reference types="Cypress" /> /// <reference types="cypress" />
describe('Certificates endpoints', () => { describe('Certificates endpoints', () => {
let token; let token;

View File

@ -1,4 +1,4 @@
/// <reference types="Cypress" /> /// <reference types="cypress" />
describe('Full Certificate Provisions', () => { describe('Full Certificate Provisions', () => {
let token; let token;

View File

@ -1,4 +1,4 @@
/// <reference types="Cypress" /> /// <reference types="cypress" />
describe('Basic API checks', () => { describe('Basic API checks', () => {
it('Should return a valid health payload', function() { it('Should return a valid health payload', function() {

View File

@ -1,4 +1,4 @@
/// <reference types="Cypress" /> /// <reference types="cypress" />
// Settings are stored lowercase in the backend // Settings are stored lowercase in the backend

View File

@ -1,4 +1,4 @@
/// <reference types="Cypress" /> /// <reference types="cypress" />
describe('Setup Phase', () => { describe('Setup Phase', () => {
@ -8,15 +8,15 @@ describe('Setup Phase', () => {
it('Should NOT be able to get a token', function() { it('Should NOT be able to get a token', function() {
cy.task('backendApiPost', { cy.task('backendApiPost', {
path: '/api/tokens', path: '/api/auth',
data: { data: {
type: 'password', type: 'local',
identity: 'cypress@example.com', identity: 'cypress@example.com',
secret: 'changeme' secret: 'changeme'
}, },
returnOnError: true returnOnError: true
}).then((data) => { }).then((data) => {
cy.validateSwaggerSchema('post', 403, '/tokens', data); cy.validateSwaggerSchema('post', 403, '/auth', data);
expect(data.error).to.have.property('code', 403); expect(data.error).to.have.property('code', 403);
expect(data.error).to.have.property('message', 'Not available during setup phase'); expect(data.error).to.have.property('message', 'Not available during setup phase');
}); });

View File

@ -1,4 +1,4 @@
/// <reference types="Cypress" /> /// <reference types="cypress" />
describe('Swagger Schema Checks', () => { describe('Swagger Schema Checks', () => {
it('Should be valid with swagger-validator', function() { it('Should be valid with swagger-validator', function() {

View File

@ -1,4 +1,4 @@
/// <reference types="Cypress" /> /// <reference types="cypress" />
describe('Upstream endpoints', () => { describe('Upstream endpoints', () => {
let token; let token;

View File

@ -1,4 +1,4 @@
/// <reference types="Cypress" /> /// <reference types="cypress" />
describe('Users endpoints', () => { describe('Users endpoints', () => {
let token; let token;
@ -82,11 +82,10 @@ describe('Users endpoints', () => {
path: '/api/users', path: '/api/users',
data: { data: {
name: 'Example user 1', name: 'Example user 1',
nickname: 'User1',
email: uniqueEmail, email: uniqueEmail,
is_disabled: false, is_disabled: false,
auth: { auth: {
type: 'password', type: 'local',
secret: 'changeme' secret: 'changeme'
}, },
capabilities: [ capabilities: [
@ -108,11 +107,10 @@ describe('Users endpoints', () => {
returnOnError: true, returnOnError: true,
data: { data: {
name: 'Example user 2', name: 'Example user 2',
nickname: 'User2',
email: uniqueEmail, email: uniqueEmail,
is_disabled: false, is_disabled: false,
auth: { auth: {
type: 'password', type: 'local',
secret: 'changeme' secret: 'changeme'
}, },
capabilities: [ capabilities: [

View File

@ -1,4 +1,4 @@
/// <reference types="Cypress" /> /// <reference types="cypress" />
describe('UI Setup and Login', () => { describe('UI Setup and Login', () => {
@ -10,7 +10,6 @@ describe('UI Setup and Login', () => {
it('Should be able to setup a new user', function() { it('Should be able to setup a new user', function() {
cy.visit('/'); cy.visit('/');
cy.get('input[name="name"]').type('Cypress McGee'); cy.get('input[name="name"]').type('Cypress McGee');
cy.get('input[name="nickname"]').type('Cypress');
cy.get('input[name="email"]').type('cypress@example.com'); cy.get('input[name="email"]').type('cypress@example.com');
cy.get('input[name="password"]').type('changeme'); cy.get('input[name="password"]').type('changeme');
cy.get('form button:last').click(); cy.get('form button:last').click();

View File

@ -66,7 +66,7 @@ Cypress.Commands.add('getToken', (defaultUser, defaultAuth) => {
}); });
} else { } else {
let auth = { let auth = {
type: 'password', type: 'local',
identity: 'cypress@example.com', identity: 'cypress@example.com',
secret: 'changeme', secret: 'changeme',
}; };
@ -78,7 +78,7 @@ Cypress.Commands.add('getToken', (defaultUser, defaultAuth) => {
cy.log('Setup = true'); cy.log('Setup = true');
// login with existing user // login with existing user
cy.task('backendApiPost', { cy.task('backendApiPost', {
path: '/api/tokens', path: '/api/auth',
data: auth, data: auth,
}).then((res) => { }).then((res) => {
cy.wrap(res.result.token); cy.wrap(res.result.token);
@ -90,11 +90,10 @@ Cypress.Commands.add('getToken', (defaultUser, defaultAuth) => {
Cypress.Commands.add('createInitialUser', (defaultUser) => { Cypress.Commands.add('createInitialUser', (defaultUser) => {
let user = { let user = {
name: 'Cypress McGee', name: 'Cypress McGee',
nickname: 'Cypress',
email: 'cypress@example.com', email: 'cypress@example.com',
is_disabled: false, is_disabled: false,
auth: { auth: {
type: 'password', type: 'local',
secret: 'changeme' secret: 'changeme'
}, },
capabilities: ['full-admin'] capabilities: ['full-admin']