mirror of
https://git.cloudron.io/cloudron/gitea-app
synced 2025-09-25 22:47:24 +00:00
Compare commits
273 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
58298a6b20 | ||
|
6b2e221264 | ||
|
1e9964fe49 | ||
|
23fa45cbc8 | ||
|
572226155c | ||
|
50ec10f0ae | ||
|
a99dfc8e2a | ||
|
6bbea49e07 | ||
|
f53e024f69 | ||
|
68fe1f97d0 | ||
|
896336f7c2 | ||
|
ea91e676cf | ||
|
94e9181ced | ||
|
8808e8c0b2 | ||
|
d00238c1ad | ||
|
07442c675c | ||
|
ed1846cd28 | ||
|
e10793d421 | ||
|
9eea9fe0be | ||
|
298cb33e86 | ||
|
89240fc070 | ||
|
6b2af3eab4 | ||
|
32eebcff8f | ||
|
166dac9b12 | ||
|
26db0254c7 | ||
|
35e3edaa6c | ||
|
93370fa502 | ||
|
3398da164d | ||
|
6ce20e9e75 | ||
|
cb14653680 | ||
|
46982e68f7 | ||
|
a2d2edabaf | ||
|
7261adc546 | ||
|
a338dc215a | ||
|
a12cf5f70b | ||
|
730611229e | ||
|
fcb4caff89 | ||
|
200dc7676f | ||
|
320fbf86d9 | ||
|
04d857e88b | ||
|
e2f6fb52b3 | ||
|
4224cc9692 | ||
|
d416ec0dc7 | ||
|
ea5ff4e574 | ||
|
27720786bf | ||
|
f48a4c4d72 | ||
|
65fbb9cb7d | ||
|
63bfe621d1 | ||
|
a6688ede57 | ||
|
7f2646bfb3 | ||
|
aafc1968ec | ||
|
2f85d288e0 | ||
|
e5296ab5ee | ||
|
77e05f56bf | ||
|
4eab21379e | ||
|
1da61b548f | ||
|
76df0b0113 | ||
|
d9fa8399fe | ||
|
aa0b00cd1e | ||
|
8999bc9112 | ||
|
a7734d29fb | ||
|
b667082cec | ||
|
9abcb0c5ec | ||
|
3f6593c676 | ||
|
5f7b0457db | ||
|
7adfed915b | ||
|
2af74e6817 | ||
|
57ad6d200a | ||
|
4df53960f5 | ||
|
2fb28433fb | ||
|
6874ea9d46 | ||
|
2c284d36fa | ||
|
83da665570 | ||
|
a427a098fe | ||
|
eb4f29375b | ||
|
05dcb14e8d | ||
|
5a03ee8f27 | ||
|
e62f99643d | ||
|
73027148c6 | ||
|
67a138be41 | ||
|
2c32dcf6bd | ||
|
dc7f7e2f4e | ||
|
9a03f268cb | ||
|
fde6dfa485 | ||
|
8b16de1dcd | ||
|
1074999c40 | ||
|
0cfe7fea88 | ||
|
a3bb9db92e | ||
|
8c84f905e7 | ||
|
0008351e7c | ||
|
0aab01b926 | ||
|
2877b4e599 | ||
|
f5f690ebd9 | ||
|
4a5bf98d60 | ||
|
3e84ab8730 | ||
|
c0d7b41a77 | ||
|
df77df2347 | ||
|
f18b11626c | ||
|
75917ed6e1 | ||
|
8033a4f001 | ||
|
6c2c00a53a | ||
|
86e13642e6 | ||
|
257b51d226 | ||
|
37544c8e9b | ||
|
a04656847a | ||
|
5e8950ec86 | ||
|
2637ef1b4b | ||
|
0bea878d12 | ||
|
bed765a1e4 | ||
|
1e38bd58c6 | ||
|
a0f8607250 | ||
|
4c0e49def0 | ||
|
c9937d6134 | ||
|
3d51637daf | ||
|
65a87ede58 | ||
|
11800518cb | ||
|
731be1ccf8 | ||
|
32c5507674 | ||
|
1deeedfc87 | ||
|
86a0949b14 | ||
|
1aee702ada | ||
|
6833bcd31b | ||
|
1a433ecee0 | ||
|
c1f261592e | ||
|
282eed291e | ||
|
43900e7897 | ||
|
5ff6e0a410 | ||
|
3b9989fcf0 | ||
|
8b92a4feb4 | ||
|
f510244950 | ||
|
8744b525cd | ||
|
172c5f7307 | ||
|
48299030e6 | ||
|
8e84cf4817 | ||
|
c263876cdd | ||
|
6429ca8909 | ||
|
0cf326f08f | ||
|
2cc40fffef | ||
|
9a3c9338c3 | ||
|
58a6351ab2 | ||
|
ef557e98d7 | ||
|
2a17c1717d | ||
|
62f9860bf5 | ||
|
522923dbee | ||
|
b117af4511 | ||
|
dc2987aafb | ||
|
50a2444e76 | ||
|
ea72f04000 | ||
|
2759c0d852 | ||
|
7b0ec195e6 | ||
|
a677369189 | ||
|
2e8b2c637f | ||
|
07d07b342a | ||
|
93fa56da6b | ||
|
e68a0333a9 | ||
|
5ed9ee9284 | ||
|
a94c165c34 | ||
|
1b053028a0 | ||
|
5e7a1b2a37 | ||
|
cc63133f85 | ||
|
08cbfbb9d4 | ||
|
9944104273 | ||
|
076dd3946b | ||
|
2885c388e8 | ||
|
8693f77352 | ||
|
5a0d2ea12e | ||
|
3fbe8140a7 | ||
|
ac4eecf92b | ||
|
3fc5685027 | ||
|
9320ee11ad | ||
|
664677527a | ||
|
b1f8b8cb9a | ||
|
b72d7ad682 | ||
|
5b625519c1 | ||
|
9551b31c8e | ||
|
4514b6fc9b | ||
|
783cce292c | ||
|
538f3fdead | ||
|
b2b86f170f | ||
|
4301fd5117 | ||
|
7aebe88c3e | ||
|
91cc96705e | ||
|
6fe012f901 | ||
|
29197622fc | ||
|
3adbf0b442 | ||
|
6c0a2ab20b | ||
|
1943723dd3 | ||
|
2d15227f2e | ||
|
cbc0bfb222 | ||
|
10df3c6ba9 | ||
|
047ec295bc | ||
|
31b8a17230 | ||
|
ebb46bb7ac | ||
|
53f180ef95 | ||
|
d89fc6a0ec | ||
|
1039d32995 | ||
|
6b25bb66c7 | ||
|
e566c94b43 | ||
|
0d2e1cfff0 | ||
|
f830faac79 | ||
|
319e6d275c | ||
|
9128339000 | ||
|
f7ca27425a | ||
|
9907d1c9cd | ||
|
8d16e4d734 | ||
|
150d490801 | ||
|
4a4e4ff4f1 | ||
|
24e9499d9c | ||
|
8c66d9ed76 | ||
|
60d06af70d | ||
|
15c28c940d | ||
|
5f5d3a7b53 | ||
|
0902b92a7d | ||
|
d675d60e1d | ||
|
07d3c6bfcf | ||
|
60f9045cbb | ||
|
a633dcab9a | ||
|
435f30cf8c | ||
|
157f500660 | ||
|
2eae86ee53 | ||
|
3993229ac3 | ||
|
9793215e7c | ||
|
6e04300610 | ||
|
587235be2b | ||
|
de3369808e | ||
|
5e99be936a | ||
|
12f58af585 | ||
|
9971919cf9 | ||
|
65bc13c2b7 | ||
|
c231b12f2d | ||
|
1265366151 | ||
|
278116abdb | ||
|
8a942dc8f7 | ||
|
1b15db85e3 | ||
|
d37044f8e0 | ||
|
e7671bd3f2 | ||
|
32cc8175e5 | ||
|
534e4884b4 | ||
|
6e1f363b88 | ||
|
3eb57f2c07 | ||
|
b16095eef5 | ||
|
18b3ae6bc2 | ||
|
fbf8e5f953 | ||
|
106e65df9e | ||
|
1b629265fa | ||
|
f9949c11a3 | ||
|
a7e693c4ed | ||
|
b00d2aced2 | ||
|
c2419ba46c | ||
|
b39e1850d7 | ||
|
4d37e33eee | ||
|
b86f9c7a20 | ||
|
7fd766b348 | ||
|
525327c150 | ||
|
bc658da61e | ||
|
25f206ccdb | ||
|
d3553de1a6 | ||
|
99379fdbb3 | ||
|
21a9fccd60 | ||
|
8837d2fd60 | ||
|
a66843c3e3 | ||
|
67403a6d2a | ||
|
c137f79e9b | ||
|
0249f20656 | ||
|
5d00e930ff | ||
|
619bd735a6 | ||
|
a59430be60 | ||
|
3e04f6b996 | ||
|
7481ed9f60 | ||
|
93e8df020f | ||
|
2329c01ba5 | ||
|
bf67824fa6 | ||
|
795e6efb0a |
25
CHANGELOG
25
CHANGELOG
@@ -1,25 +0,0 @@
|
|||||||
[0.1.0]
|
|
||||||
* Initial package (forked from Gogs app)
|
|
||||||
|
|
||||||
[0.1.1]
|
|
||||||
* Removed reference to Gogs
|
|
||||||
|
|
||||||
[0.1.2]
|
|
||||||
* Updated description
|
|
||||||
|
|
||||||
[0.1.3]
|
|
||||||
* Updated to version 1.1.2
|
|
||||||
|
|
||||||
[1.0.0]
|
|
||||||
* Update to version 1.1.3
|
|
||||||
|
|
||||||
[1.0.1]
|
|
||||||
* Update Git to v2.7.4-0ubuntu1.2
|
|
||||||
* Fixes critical security issue that allows remote command execution in git
|
|
||||||
* https://people.canonical.com/~ubuntu-security/cve/2017/CVE-2017-1000117.html
|
|
||||||
|
|
||||||
[1.0.2]
|
|
||||||
* Preserve SECRET_KEY across updates and restarts
|
|
||||||
|
|
||||||
[1.0.3]
|
|
||||||
* Update to version 1.1.4
|
|
1173
CHANGELOG.md
Normal file
1173
CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -4,13 +4,15 @@
|
|||||||
"author": "Gitea developers",
|
"author": "Gitea developers",
|
||||||
"description": "file://DESCRIPTION.md",
|
"description": "file://DESCRIPTION.md",
|
||||||
"tagline": "A painless self-hosted Git Service",
|
"tagline": "A painless self-hosted Git Service",
|
||||||
"version": "1.0.3",
|
"version": "1.27.1",
|
||||||
"healthCheckPath": "/healthcheck",
|
"upstreamVersion": "1.18.5",
|
||||||
|
"healthCheckPath": "/explore",
|
||||||
"httpPort": 3000,
|
"httpPort": 3000,
|
||||||
|
"memoryLimit": 536870912,
|
||||||
"addons": {
|
"addons": {
|
||||||
"mysql": { },
|
"mysql": { },
|
||||||
"sendmail": { },
|
"sendmail": { },
|
||||||
"localstorage": { },
|
"localstorage": { "supportsDisplayName": true },
|
||||||
"ldap": { }
|
"ldap": { }
|
||||||
},
|
},
|
||||||
"tcpPorts": {
|
"tcpPorts": {
|
||||||
@@ -20,18 +22,22 @@
|
|||||||
"defaultValue": 29418
|
"defaultValue": 29418
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"manifestVersion": 1,
|
"manifestVersion": 2,
|
||||||
"website": "https://gitea.io",
|
"website": "https://gitea.io",
|
||||||
"contactEmail": "apps@cloudron.io",
|
"contactEmail": "apps@cloudron.io",
|
||||||
"icon": "file://logo.png",
|
"icon": "file://logo.png",
|
||||||
|
"optionalSso": true,
|
||||||
"mediaLinks": [
|
"mediaLinks": [
|
||||||
"https://s3.amazonaws.com/cloudron-app-screenshots/io.gitea.cloudronapp/f89a2ab8d49094c80589f69a2d60bef63b2dbb62/1.png",
|
"https://screenshots.cloudron.io/io.gitea.cloudronapp/1.png",
|
||||||
"https://s3.amazonaws.com/cloudron-app-screenshots/io.gitea.cloudronapp/f89a2ab8d49094c80589f69a2d60bef63b2dbb62/2.png",
|
"https://screenshots.cloudron.io/io.gitea.cloudronapp/2.png",
|
||||||
"https://s3.amazonaws.com/cloudron-app-screenshots/io.gitea.cloudronapp/f89a2ab8d49094c80589f69a2d60bef63b2dbb62/3.png",
|
"https://screenshots.cloudron.io/io.gitea.cloudronapp/3.png",
|
||||||
"https://s3.amazonaws.com/cloudron-app-screenshots/io.gitea.cloudronapp/f89a2ab8d49094c80589f69a2d60bef63b2dbb62/4.png",
|
"https://screenshots.cloudron.io/io.gitea.cloudronapp/4.png",
|
||||||
"https://s3.amazonaws.com/cloudron-app-screenshots/io.gitea.cloudronapp/f89a2ab8d49094c80589f69a2d60bef63b2dbb62/5.png"
|
"https://screenshots.cloudron.io/io.gitea.cloudronapp/5.png"
|
||||||
],
|
],
|
||||||
"tags": [ "version control", "git", "code hosting", "development" ],
|
"tags": [ "version control", "git", "code hosting", "development", "github", "bitbucket", "gitlab" ],
|
||||||
"changelog": "file://CHANGELOG",
|
"changelog": "file://CHANGELOG.md",
|
||||||
"postInstallMessage": "file://POSTINSTALL.md"
|
"postInstallMessage": "file://POSTINSTALL.md",
|
||||||
|
"minBoxVersion": "7.3.0",
|
||||||
|
"forumUrl": "https://forum.cloudron.io/category/19/gitea",
|
||||||
|
"documentationUrl": "https://docs.cloudron.io/apps/gitea/"
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
Gitea is a painless self-hosted Git service. It is similar to GitHub, Bitbucket or Gitlab. The initial development have been done on Gogs but we have forked it and named it Gitea. If you want to read more about the reasons why we have done that please read [this](https://blog.gitea.io/2016/12/welcome-to-gitea/) blog post.
|
Gitea is a painless self-hosted Git service. It is similar to GitHub, Bitbucket or Gitlab.
|
||||||
|
|
||||||
This app packages Gitea <upstream>1.1.4</upstream>
|
|
||||||
|
|
||||||
### Purpose
|
### Purpose
|
||||||
|
|
||||||
|
19
Dockerfile
19
Dockerfile
@@ -1,11 +1,10 @@
|
|||||||
FROM cloudron/base:0.10.0
|
FROM cloudron/base:4.0.0@sha256:31b195ed0662bdb06a6e8a5ddbedb6f191ce92e8bee04c03fb02dd4e9d0286df
|
||||||
|
|
||||||
ENV VERSION 1.1.4
|
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y openssh-server git && \
|
apt-get install -y openssh-server git asciidoctor pandoc && \
|
||||||
rm -rf /etc/ssh_host_* && \
|
rm -rf /etc/ssh_host_* && \
|
||||||
rm -r /var/cache/apt /var/lib/apt/lists
|
rm -r /var/cache/apt /var/lib/apt/lists
|
||||||
|
RUN pip3 install jupyter
|
||||||
|
|
||||||
ADD supervisor/ /etc/supervisor/conf.d/
|
ADD supervisor/ /etc/supervisor/conf.d/
|
||||||
|
|
||||||
@@ -15,7 +14,13 @@ RUN adduser --disabled-login --gecos 'Gitea' git
|
|||||||
RUN passwd -d git
|
RUN passwd -d git
|
||||||
|
|
||||||
RUN mkdir -p /home/git/gitea
|
RUN mkdir -p /home/git/gitea
|
||||||
## TODO: use redis as well
|
WORKDIR /home/git
|
||||||
|
|
||||||
|
# for autosign feature
|
||||||
|
ENV GNUPGHOME="/app/data/gnupg"
|
||||||
|
|
||||||
|
ARG VERSION=1.18.5
|
||||||
|
|
||||||
RUN curl -L https://dl.gitea.io/gitea/${VERSION}/gitea-${VERSION}-linux-amd64 -o /home/git/gitea/gitea \
|
RUN curl -L https://dl.gitea.io/gitea/${VERSION}/gitea-${VERSION}-linux-amd64 -o /home/git/gitea/gitea \
|
||||||
&& chmod +x /home/git/gitea/gitea
|
&& chmod +x /home/git/gitea/gitea
|
||||||
|
|
||||||
@@ -31,9 +36,7 @@ RUN ln -s /app/data/gitconfig /home/git/.gitconfig
|
|||||||
|
|
||||||
ADD start.sh /home/git/start.sh
|
ADD start.sh /home/git/start.sh
|
||||||
|
|
||||||
# disable pam authentication for sshd
|
COPY sshd_config /etc/ssh/sshd_config
|
||||||
RUN sed -e 's/UsePAM yes/UsePAM no/' -e 's/UsePrivilegeSeparation yes/UsePrivilegeSeparation no/' -i /etc/ssh/sshd_config
|
|
||||||
RUN echo "UseDNS no" >> /etc/ssh/sshd_config
|
|
||||||
|
|
||||||
CMD [ "/home/git/start.sh" ]
|
CMD [ "/home/git/start.sh" ]
|
||||||
|
|
||||||
|
@@ -1,12 +1,8 @@
|
|||||||
This app integrates with the Cloudron SSO. Admins on Cloudron automatically
|
This app is pre-setup with an admin account (use the `Local` authentication source for logging in as admin).
|
||||||
become admins on Gitea.
|
The initial credentials are:
|
||||||
|
|
||||||
If you want to disable Cloudron SSO, do the following:
|
**Username**: root<br/>
|
||||||
|
**Password**: changeme<br/>
|
||||||
|
|
||||||
* Admin Panel -> Authentication -> 'cloudron' -> Uncheck 'This authentication is activated'
|
Please change the admin password immediately.
|
||||||
* Admin Panel -> Users -> Change Authentication Source to 'Local' and also give a password
|
|
||||||
|
|
||||||
You can edit `/app/data/app.ini` and add any custom configuration. See the
|
|
||||||
[configuration cheat sheet](https://docs.gitea.io/en-us/config-cheat-sheet)
|
|
||||||
for more information.
|
|
||||||
|
|
||||||
|
@@ -64,7 +64,8 @@ SKIP_VERIFY = true
|
|||||||
; those settings are protected and can't be modified
|
; those settings are protected and can't be modified
|
||||||
INSTALL_LOCK = true
|
INSTALL_LOCK = true
|
||||||
SECRET_KEY = ##SECRET_KEY
|
SECRET_KEY = ##SECRET_KEY
|
||||||
|
REVERSE_PROXY_LIMIT = 1
|
||||||
|
REVERSE_PROXY_TRUSTED_PROXIES = *
|
||||||
|
|
||||||
[service]
|
[service]
|
||||||
DISABLE_REGISTRATION = false
|
DISABLE_REGISTRATION = false
|
||||||
@@ -95,3 +96,32 @@ PATH =
|
|||||||
[indexer]
|
[indexer]
|
||||||
; this setting is protected and can't be modified
|
; this setting is protected and can't be modified
|
||||||
ISSUE_INDEXER_PATH = /app/data/appdata/indexers/issues.bleve
|
ISSUE_INDEXER_PATH = /app/data/appdata/indexers/issues.bleve
|
||||||
|
|
||||||
|
[session]
|
||||||
|
PROVIDER = file
|
||||||
|
PROVIDER_CONFIG = /run/gitea/sessions
|
||||||
|
COOKIE_SECURE = true
|
||||||
|
COOKIE_NAME = cloudron_gitea
|
||||||
|
GC_INTERVAL_TIME = 2592000
|
||||||
|
|
||||||
|
[markup.asciidoc]
|
||||||
|
ENABLED = true
|
||||||
|
FILE_EXTENSIONS = .adoc,.asciidoc
|
||||||
|
RENDER_COMMAND = "asciidoctor -s -a showtitle --out-file=- -"
|
||||||
|
; Input is not a standard input but a file
|
||||||
|
IS_INPUT_FILE = false
|
||||||
|
|
||||||
|
[markup.restructuredtext]
|
||||||
|
ENABLED = true
|
||||||
|
FILE_EXTENSIONS = .rst
|
||||||
|
RENDER_COMMAND = "timeout 30s pandoc +RTS -M512M -RTS -f rst"
|
||||||
|
IS_INPUT_FILE = false
|
||||||
|
|
||||||
|
[markup.jupyter]
|
||||||
|
ENABLED = true
|
||||||
|
FILE_EXTENSIONS = .ipynb
|
||||||
|
RENDER_COMMAND = "jupyter nbconvert --stdin --stdout --to html --template basic"
|
||||||
|
IS_INPUT_FILE = false
|
||||||
|
|
||||||
|
[markup.sanitizer.jupyter.img]
|
||||||
|
ALLOW_DATA_URI_IMAGES = true
|
||||||
|
BIN
logo.png
BIN
logo.png
Binary file not shown.
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 8.9 KiB |
80
sshd_config
Normal file
80
sshd_config
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
# Package generated configuration file
|
||||||
|
# See the sshd_config(5) manpage for details
|
||||||
|
|
||||||
|
# What ports, IPs and protocols we listen for
|
||||||
|
Port 29418
|
||||||
|
# Use these options to restrict which interfaces/protocols sshd will bind to
|
||||||
|
ListenAddress 0.0.0.0
|
||||||
|
ListenAddress ::
|
||||||
|
Protocol 2
|
||||||
|
# HostKeys for protocol version 2
|
||||||
|
HostKey /app/data/sshd/ssh_host_rsa_key
|
||||||
|
HostKey /app/data/sshd/ssh_host_dsa_key
|
||||||
|
HostKey /app/data/sshd/ssh_host_ecdsa_key
|
||||||
|
HostKey /app/data/sshd/ssh_host_ed25519_key
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
SyslogFacility AUTH
|
||||||
|
LogLevel INFO
|
||||||
|
|
||||||
|
# Authentication:
|
||||||
|
LoginGraceTime 120
|
||||||
|
PermitRootLogin prohibit-password
|
||||||
|
StrictModes yes
|
||||||
|
|
||||||
|
PubkeyAuthentication yes
|
||||||
|
#AuthorizedKeysFile %h/.ssh/authorized_keys
|
||||||
|
|
||||||
|
# Don't read the user's ~/.rhosts and ~/.shosts files
|
||||||
|
IgnoreRhosts yes
|
||||||
|
# similar for protocol version 2
|
||||||
|
HostbasedAuthentication no
|
||||||
|
# Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication
|
||||||
|
#IgnoreUserKnownHosts yes
|
||||||
|
|
||||||
|
# To enable empty passwords, change to yes (NOT RECOMMENDED)
|
||||||
|
PermitEmptyPasswords no
|
||||||
|
|
||||||
|
# Change to yes to enable challenge-response passwords (beware issues with
|
||||||
|
# some PAM modules and threads)
|
||||||
|
ChallengeResponseAuthentication no
|
||||||
|
|
||||||
|
# Change to no to disable tunnelled clear text passwords
|
||||||
|
#PasswordAuthentication yes
|
||||||
|
|
||||||
|
# Kerberos options
|
||||||
|
#KerberosAuthentication no
|
||||||
|
#KerberosGetAFSToken no
|
||||||
|
#KerberosOrLocalPasswd yes
|
||||||
|
#KerberosTicketCleanup yes
|
||||||
|
|
||||||
|
# GSSAPI options
|
||||||
|
#GSSAPIAuthentication no
|
||||||
|
#GSSAPICleanupCredentials yes
|
||||||
|
|
||||||
|
X11Forwarding yes
|
||||||
|
X11DisplayOffset 10
|
||||||
|
PrintMotd no
|
||||||
|
PrintLastLog yes
|
||||||
|
TCPKeepAlive yes
|
||||||
|
#UseLogin no
|
||||||
|
|
||||||
|
#MaxStartups 10:30:60
|
||||||
|
#Banner /etc/issue.net
|
||||||
|
|
||||||
|
# Allow client to pass locale environment variables
|
||||||
|
AcceptEnv LANG LC_*
|
||||||
|
|
||||||
|
Subsystem sftp /usr/lib/openssh/sftp-server
|
||||||
|
|
||||||
|
# Set this to 'yes' to enable PAM authentication, account processing,
|
||||||
|
# and session processing. If this is enabled, PAM authentication will
|
||||||
|
# be allowed through the ChallengeResponseAuthentication and
|
||||||
|
# PasswordAuthentication. Depending on your PAM configuration,
|
||||||
|
# PAM authentication via ChallengeResponseAuthentication may bypass
|
||||||
|
# the setting of "PermitRootLogin without-password".
|
||||||
|
# If you just want the PAM account and session checks to run without
|
||||||
|
# PAM authentication, then enable this but set PasswordAuthentication
|
||||||
|
# and ChallengeResponseAuthentication to 'no'.
|
||||||
|
UsePAM no
|
||||||
|
UseDNS no
|
105
start.sh
105
start.sh
@@ -2,32 +2,63 @@
|
|||||||
|
|
||||||
set -eu -o pipefail
|
set -eu -o pipefail
|
||||||
|
|
||||||
mkdir -p /run/gitea/tmp/uploads
|
mkdir -p /run/gitea/tmp/uploads /run/sshd /run/gitea/sessions
|
||||||
|
|
||||||
setup_ldap_source() {
|
setup_ldap_source() {
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
# Wait for gitea to finish db setup, before we insert ldap source in db
|
echo "==> Setup LDAP source"
|
||||||
while ! curl --fail http://localhost:3000/healthcheck; do
|
|
||||||
echo "Waiting for gitea to come up"
|
# Get the existing LDAP source status. This allows the user to disable LDAP
|
||||||
sleep 1
|
# Note that this method is deprecated since this app now supports optionalSso
|
||||||
done
|
ldap_status=$(mysql -u"${CLOUDRON_MYSQL_USERNAME}" -p"${CLOUDRON_MYSQL_PASSWORD}" -h mysql --database="${CLOUDRON_MYSQL_DATABASE}" -N -B -e "select is_active from login_source WHERE name='cloudron';")
|
||||||
|
[[ -z "${ldap_status}" ]] && ldap_status="1"
|
||||||
|
|
||||||
now=$(date +%s)
|
now=$(date +%s)
|
||||||
|
|
||||||
# Get the existing LDAP source status. This allows the user to disable LDAP
|
if mysql -u"${CLOUDRON_MYSQL_USERNAME}" -p"${CLOUDRON_MYSQL_PASSWORD}" -h mysql --database="${CLOUDRON_MYSQL_DATABASE}" \
|
||||||
ldap_status=$(mysql -u"${MYSQL_USERNAME}" -p"${MYSQL_PASSWORD}" -h mysql --database="${MYSQL_DATABASE}" -N -B -e "select is_actived from login_source WHERE name='cloudron';")
|
-e "REPLACE INTO login_source (id, type, name, is_active, cfg, created_unix, updated_unix) VALUES (1,2,'cloudron',${ldap_status},'{\"Name\":\"cloudron\",\"Host\":\"${CLOUDRON_LDAP_SERVER}\",\"Port\":${CLOUDRON_LDAP_PORT},\"UseSSL\":false,\"SkipVerify\":true,\"BindDN\":\"${CLOUDRON_LDAP_BIND_DN}\",\"BindPassword\":\"${CLOUDRON_LDAP_BIND_PASSWORD}\",\"UserBase\":\"${CLOUDRON_LDAP_USERS_BASE_DN}\",\"AttributeUsername\":\"username\",\"AttributeName\":\"displayname\",\"AttributeSurname\":\"\",\"AttributeMail\":\"mail\",\"Filter\":\"(\\\\u007C(mail=%[1]s)(username=%[1]s))\"}','${now}','${now}');"; then
|
||||||
[[ -z "${ldap_status}" ]] && ldap_status="1"
|
echo "==> LDAP Authentication was setup with activation status ${ldap_status}"
|
||||||
|
|
||||||
if mysql -u"${MYSQL_USERNAME}" -p"${MYSQL_PASSWORD}" -h mysql --database="${MYSQL_DATABASE}" \
|
|
||||||
-e "REPLACE INTO login_source (id, type, name, is_actived, cfg, created_unix, updated_unix) VALUES (1,2,'cloudron',${ldap_status},'{\"Name\":\"cloudron\",\"Host\":\"${LDAP_SERVER}\",\"Port\":${LDAP_PORT},\"UseSSL\":false,\"SkipVerify\":true,\"BindDN\":\"${LDAP_BIND_DN}\",\"BindPassword\":\"${LDAP_BIND_PASSWORD}\",\"UserBase\":\"${LDAP_USERS_BASE_DN}\",\"AttributeUsername\":\"username\",\"AttributeName\":\"displayname\",\"AttributeSurname\":\"\",\"AttributeMail\":\"mail\",\"Filter\":\"(\\\\u007C(mail=%[1]s)(username=%[1]s))\",\"AdminFilter\":\"(memberof=cn=admins,${LDAP_GROUPS_BASE_DN})\"}','${now}','${now}');"; then
|
|
||||||
echo "LDAP Authentication was setup with status ${ldap_status}"
|
|
||||||
else
|
else
|
||||||
echo "Failed to setup LDAP authentication"
|
echo "==> Failed to setup LDAP authentication"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup_root_user() {
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
if sudo -H -u git /home/git/gitea/gitea admin user create --username root --password changeme --email admin@cloudron.local --admin -c /run/gitea/app.ini; then
|
||||||
|
echo "==> root user added"
|
||||||
|
else
|
||||||
|
echo "==> Failed to add root user"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_auth() {
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
# Wait for gitea to finish db setup, before we do any db operations
|
||||||
|
while ! curl --fail http://localhost:3000/explore; do
|
||||||
|
echo "==> Waiting for gitea to come up"
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "==> Gitea is up, setting up auth"
|
||||||
|
|
||||||
|
if [[ -n "${CLOUDRON_LDAP_SERVER:-}" ]]; then
|
||||||
|
setup_ldap_source
|
||||||
|
fi
|
||||||
|
|
||||||
|
user_count=$(mysql -u"${CLOUDRON_MYSQL_USERNAME}" -p"${CLOUDRON_MYSQL_PASSWORD}" -h mysql --database="${CLOUDRON_MYSQL_DATABASE}" -N -B -e "SELECT count(*) FROM user;")
|
||||||
|
# be careful, not to create root user for existing LDAP based installs
|
||||||
|
if [[ "${user_count}" == "0" ]]; then
|
||||||
|
echo "==> Setting up root user for first run"
|
||||||
|
setup_root_user
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# SSH_PORT can be unset to disable SSH
|
# SSH_PORT can be unset to disable SSH
|
||||||
disable_ssh="false"
|
disable_ssh="false"
|
||||||
if [[ -z "${SSH_PORT:-}" ]]; then
|
if [[ -z "${SSH_PORT:-}" ]]; then
|
||||||
@@ -50,35 +81,28 @@ fi
|
|||||||
chmod 0600 /app/data/sshd/*_key
|
chmod 0600 /app/data/sshd/*_key
|
||||||
chmod 0644 /app/data/sshd/*.pub
|
chmod 0644 /app/data/sshd/*.pub
|
||||||
|
|
||||||
sed -e "s/^Port .*/Port ${SSH_PORT}/" \
|
sed -e "s/^Port .*/Port ${SSH_PORT}/" /etc/ssh/sshd_config > /run/gitea/sshd_config
|
||||||
-e "s/^#ListenAddress .*/ListenAddress 0.0.0.0/" \
|
|
||||||
-e "s,^HostKey /etc/ssh/,HostKey /app/data/sshd/," \
|
|
||||||
/etc/ssh/sshd_config > /run/gitea/sshd_config
|
|
||||||
|
|
||||||
cp /home/git/app.ini.template "/run/gitea/app.ini"
|
if [[ ! -f /app/data/app.ini ]]; then
|
||||||
|
echo -e "; Add customizations here - https://docs.gitea.io/en-us/config-cheat-sheet/" > /app/data/app.ini
|
||||||
|
|
||||||
# create default user config file
|
echo "==> Generating new SECRET_KEY"
|
||||||
if ! [ -f /app/data/app.ini ]; then
|
|
||||||
cp /home/git/app.ini.template /app/data/app.ini
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$(crudini --get /app/data/app.ini security SECRET_KEY)" == "##SECRET_KEY" ]; then
|
|
||||||
echo "Generating new SECRET_KEY"
|
|
||||||
crudini --set "/app/data/app.ini" security SECRET_KEY $(pwgen -1 -s)
|
crudini --set "/app/data/app.ini" security SECRET_KEY $(pwgen -1 -s)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# merge user config file
|
# merge user config file
|
||||||
|
cp /home/git/app.ini.template "/run/gitea/app.ini"
|
||||||
crudini --merge "/run/gitea/app.ini" < "/app/data/app.ini"
|
crudini --merge "/run/gitea/app.ini" < "/app/data/app.ini"
|
||||||
|
|
||||||
# override important values
|
# override important values
|
||||||
crudini --set "/run/gitea/app.ini" database DB_TYPE mysql
|
crudini --set "/run/gitea/app.ini" database DB_TYPE mysql
|
||||||
crudini --set "/run/gitea/app.ini" database HOST "${MYSQL_HOST}:${MYSQL_PORT}"
|
crudini --set "/run/gitea/app.ini" database HOST "${CLOUDRON_MYSQL_HOST}:${CLOUDRON_MYSQL_PORT}"
|
||||||
crudini --set "/run/gitea/app.ini" database NAME "${MYSQL_DATABASE}"
|
crudini --set "/run/gitea/app.ini" database NAME "${CLOUDRON_MYSQL_DATABASE}"
|
||||||
crudini --set "/run/gitea/app.ini" database USER "${MYSQL_USERNAME}"
|
crudini --set "/run/gitea/app.ini" database USER "${CLOUDRON_MYSQL_USERNAME}"
|
||||||
crudini --set "/run/gitea/app.ini" database PASSWD "${MYSQL_PASSWORD}"
|
crudini --set "/run/gitea/app.ini" database PASSWD "${CLOUDRON_MYSQL_PASSWORD}"
|
||||||
crudini --set "/run/gitea/app.ini" database SSL_MODE "disable"
|
crudini --set "/run/gitea/app.ini" database SSL_MODE "disable"
|
||||||
crudini --set "/run/gitea/app.ini" server PROTOCOL "http"
|
crudini --set "/run/gitea/app.ini" server PROTOCOL "http"
|
||||||
crudini --set "/run/gitea/app.ini" server DOMAIN "${APP_DOMAIN}"
|
crudini --set "/run/gitea/app.ini" server DOMAIN "${CLOUDRON_APP_DOMAIN}"
|
||||||
crudini --set "/run/gitea/app.ini" server ROOT_URL "https://%(DOMAIN)s/"
|
crudini --set "/run/gitea/app.ini" server ROOT_URL "https://%(DOMAIN)s/"
|
||||||
crudini --set "/run/gitea/app.ini" server HTTP_ADDR ""
|
crudini --set "/run/gitea/app.ini" server HTTP_ADDR ""
|
||||||
crudini --set "/run/gitea/app.ini" server HTTP_PORT "3000"
|
crudini --set "/run/gitea/app.ini" server HTTP_PORT "3000"
|
||||||
@@ -87,22 +111,23 @@ crudini --set "/run/gitea/app.ini" server SSH_PORT "${SSH_PORT}"
|
|||||||
crudini --set "/run/gitea/app.ini" server APP_DATA_PATH "/app/data/appdata"
|
crudini --set "/run/gitea/app.ini" server APP_DATA_PATH "/app/data/appdata"
|
||||||
crudini --set "/run/gitea/app.ini" repository ROOT "/app/data/repository"
|
crudini --set "/run/gitea/app.ini" repository ROOT "/app/data/repository"
|
||||||
crudini --set "/run/gitea/app.ini" repository.upload TEMP_PATH "/run/gitea/tmp/uploads"
|
crudini --set "/run/gitea/app.ini" repository.upload TEMP_PATH "/run/gitea/tmp/uploads"
|
||||||
crudini --set "/run/gitea/app.ini" mailer HOST "${MAIL_SMTP_SERVER}:${MAIL_SMTP_PORT}"
|
crudini --set "/run/gitea/app.ini" mailer HOST "${CLOUDRON_MAIL_SMTP_SERVER}:${CLOUDRON_MAIL_SMTPS_PORT}"
|
||||||
crudini --set "/run/gitea/app.ini" mailer USER "${MAIL_SMTP_USERNAME}"
|
crudini --set "/run/gitea/app.ini" mailer USER "${CLOUDRON_MAIL_SMTP_USERNAME}"
|
||||||
crudini --set "/run/gitea/app.ini" mailer PASSWD "${MAIL_SMTP_PASSWORD}"
|
crudini --set "/run/gitea/app.ini" mailer PASSWD "${CLOUDRON_MAIL_SMTP_PASSWORD}"
|
||||||
crudini --set "/run/gitea/app.ini" mailer FROM "${MAIL_FROM}"
|
crudini --set "/run/gitea/app.ini" mailer FROM "${CLOUDRON_MAIL_FROM_DISPLAY_NAME:-Gitea} <${CLOUDRON_MAIL_FROM}>"
|
||||||
crudini --set "/run/gitea/app.ini" mailer SKIP_VERIFY "true"
|
crudini --set "/run/gitea/app.ini" mailer SKIP_VERIFY "true"
|
||||||
crudini --set "/run/gitea/app.ini" security INSTALL_LOCK "true"
|
crudini --set "/run/gitea/app.ini" security INSTALL_LOCK "true"
|
||||||
|
crudini --set "/run/gitea/app.ini" security REVERSE_PROXY_LIMIT 1
|
||||||
|
crudini --set "/run/gitea/app.ini" security REVERSE_PROXY_TRUSTED_PROXIES "*"
|
||||||
crudini --set "/run/gitea/app.ini" log MODE "console"
|
crudini --set "/run/gitea/app.ini" log MODE "console"
|
||||||
crudini --set "/run/gitea/app.ini" log ROOT_PATH "/run/gitea"
|
crudini --set "/run/gitea/app.ini" log ROOT_PATH "/run/gitea"
|
||||||
crudini --set "/run/gitea/app.ini" indexer ISSUE_INDEXER_PATH "/app/data/appdata/indexers/issues.bleve"
|
crudini --set "/run/gitea/app.ini" indexer ISSUE_INDEXER_PATH "/app/data/appdata/indexers/issues.bleve"
|
||||||
|
|
||||||
|
echo "==> Creating dirs and changing permissions"
|
||||||
mkdir -p /app/data/repository /app/data/ssh
|
mkdir -p /app/data/repository /app/data/ssh /app/data/custom /app/data/gnupg
|
||||||
|
|
||||||
chown -R git:git /app/data /run/gitea
|
chown -R git:git /app/data /run/gitea
|
||||||
|
|
||||||
( setup_ldap_source ) &
|
# this expects app.ini to be available
|
||||||
|
( setup_auth ) &
|
||||||
|
|
||||||
exec /usr/bin/supervisord --configuration /etc/supervisor/supervisord.conf --nodaemon -i Gitea
|
exec /usr/bin/supervisord --configuration /etc/supervisor/supervisord.conf --nodaemon -i Gitea
|
||||||
|
|
||||||
|
@@ -9,4 +9,4 @@ stdout_logfile=/dev/stdout
|
|||||||
stdout_logfile_maxbytes=0
|
stdout_logfile_maxbytes=0
|
||||||
stderr_logfile=/dev/stderr
|
stderr_logfile=/dev/stderr
|
||||||
stderr_logfile_maxbytes=0
|
stderr_logfile_maxbytes=0
|
||||||
environment=HOME="/home/git",USER="git"
|
environment=HOME="/home/git",USER="git",GITEA_CUSTOM="/app/data/custom"
|
||||||
|
@@ -8,4 +8,3 @@ stdout_logfile=/dev/stdout
|
|||||||
stdout_logfile_maxbytes=0
|
stdout_logfile_maxbytes=0
|
||||||
stderr_logfile=/dev/stderr
|
stderr_logfile=/dev/stderr
|
||||||
stderr_logfile_maxbytes=0
|
stderr_logfile_maxbytes=0
|
||||||
|
|
||||||
|
2548
test/package-lock.json
generated
Normal file
2548
test/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,17 +8,11 @@
|
|||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
|
||||||
"ejs": "^2.3.4",
|
|
||||||
"expect.js": "^0.3.1",
|
|
||||||
"mkdirp": "^0.5.1",
|
|
||||||
"mocha": "^2.3.4",
|
|
||||||
"rimraf": "^2.4.4",
|
|
||||||
"superagent": "^1.4.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"selenium-server-standalone-jar": "^3.3.1",
|
"chromedriver": "^110.0.0",
|
||||||
"selenium-webdriver": "^3.3.0",
|
"expect.js": "^0.3.1",
|
||||||
"superagent": "^1.8.5"
|
"mocha": "^10.2.0",
|
||||||
|
"selenium-webdriver": "^4.8.1",
|
||||||
|
"superagent": "^8.0.9"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
368
test/test.js
368
test/test.js
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
/* jslint node:true */
|
/* jshint esversion: 8 */
|
||||||
/* global it:false */
|
/* global it:false */
|
||||||
/* global xit:false */
|
/* global xit:false */
|
||||||
/* global describe:false */
|
/* global describe:false */
|
||||||
@@ -9,228 +9,181 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var execSync = require('child_process').execSync,
|
require('chromedriver');
|
||||||
ejs = require('ejs'),
|
|
||||||
|
const execSync = require('child_process').execSync,
|
||||||
expect = require('expect.js'),
|
expect = require('expect.js'),
|
||||||
fs = require('fs'),
|
fs = require('fs'),
|
||||||
mkdirp = require('mkdirp'),
|
|
||||||
path = require('path'),
|
path = require('path'),
|
||||||
rimraf = require('rimraf'),
|
|
||||||
superagent = require('superagent'),
|
superagent = require('superagent'),
|
||||||
webdriver = require('selenium-webdriver');
|
{ Builder, By, until } = require('selenium-webdriver'),
|
||||||
|
{ Options } = require('selenium-webdriver/chrome');
|
||||||
|
|
||||||
var by = require('selenium-webdriver').By,
|
if (!process.env.USERNAME || !process.env.PASSWORD || !process.env.EMAIL) {
|
||||||
until = require('selenium-webdriver').until,
|
console.log('USERNAME, PASSWORD and EMAIL env vars need to be set');
|
||||||
Builder = require('selenium-webdriver').Builder;
|
process.exit(1);
|
||||||
|
}
|
||||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
||||||
|
|
||||||
describe('Application life cycle test', function () {
|
describe('Application life cycle test', function () {
|
||||||
this.timeout(0);
|
this.timeout(0);
|
||||||
var server, browser = new Builder().forBrowser('chrome').build();
|
|
||||||
|
var TIMEOUT = parseInt(process.env.TIMEOUT, 10) || 5000;
|
||||||
|
var EXEC_ARGS = { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' };
|
||||||
var LOCATION = 'test';
|
var LOCATION = 'test';
|
||||||
|
var SSH_PORT = 29420;
|
||||||
|
|
||||||
|
var app;
|
||||||
|
var browser;
|
||||||
|
|
||||||
var repodir = '/tmp/testrepo';
|
var repodir = '/tmp/testrepo';
|
||||||
var app, reponame = 'testrepo';
|
var reponame = 'testrepo';
|
||||||
|
|
||||||
var username = process.env.USERNAME;
|
var username = process.env.USERNAME;
|
||||||
var password = process.env.PASSWORD;
|
var password = process.env.PASSWORD;
|
||||||
var TIMEOUT = parseInt(process.env.TIMEOUT, 10) || 5000;
|
var email = process.env.EMAIL;
|
||||||
var email, token;
|
|
||||||
|
|
||||||
before(function (done) {
|
before(function () {
|
||||||
if (!process.env.USERNAME) return done(new Error('USERNAME env var not set'));
|
browser = new Builder().forBrowser('chrome').setChromeOptions(new Options().windowSize({ width: 1280, height: 1024 })).build();
|
||||||
if (!process.env.PASSWORD) return done(new Error('PASSWORD env var not set'));
|
|
||||||
|
|
||||||
var seleniumJar= require('selenium-server-standalone-jar');
|
|
||||||
var SeleniumServer = require('selenium-webdriver/remote').SeleniumServer;
|
|
||||||
server = new SeleniumServer(seleniumJar.path, { port: 4444 });
|
|
||||||
server.start();
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(function (done) {
|
after(function () {
|
||||||
browser.quit();
|
browser.quit();
|
||||||
server.stop();
|
fs.rmSync(repodir, { recursive: true, force: true });
|
||||||
rimraf.sync(repodir);
|
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function waitForUrl(url, done) {
|
|
||||||
browser.wait(function () {
|
|
||||||
return browser.getCurrentUrl().then(function (currentUrl) {
|
|
||||||
return currentUrl === url;
|
|
||||||
});
|
|
||||||
}, TIMEOUT).then(function () { done(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAppInfo() {
|
function getAppInfo() {
|
||||||
var inspect = JSON.parse(execSync('cloudron inspect'));
|
var inspect = JSON.parse(execSync('cloudron inspect'));
|
||||||
|
app = inspect.apps.filter(function (a) { return a.location.indexOf(LOCATION) === 0; })[0];
|
||||||
app = inspect.apps.filter(function (a) { return a.location === LOCATION; })[0];
|
|
||||||
|
|
||||||
expect(app).to.be.an('object');
|
expect(app).to.be.an('object');
|
||||||
}
|
}
|
||||||
|
|
||||||
function setAvatar(done) {
|
function sleep(millis) {
|
||||||
browser.get('https://' + app.fqdn + '/user/settings/avatar').then(function () {
|
return new Promise(resolve => setTimeout(resolve, millis));
|
||||||
return browser.findElement(by.xpath('//input[@type="file" and @name="avatar"]')).sendKeys(path.resolve(__dirname, '../logo.png'));
|
|
||||||
}).then(function () {
|
|
||||||
return browser.findElement(by.xpath('//button[contains(text(), "Update Avatar Setting")]')).click();
|
|
||||||
}).then(function () {
|
|
||||||
browser.wait(until.elementLocated(by.xpath('//p[contains(text(),"updated successfully")]')), TIMEOUT).then(function () { done(); });
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkAvatar(done) {
|
async function setAvatar() {
|
||||||
superagent.get('https://' + app.fqdn + '/avatars/a3e6f3316fc1738e29d621e6a26e93d3').end(function (error, result) {
|
await browser.get('https://' + app.fqdn + '/user/settings');
|
||||||
expect(error).to.be(null);
|
|
||||||
expect(result.statusCode).to.be(200);
|
var button = await browser.findElement(By.xpath('//label[contains(text(), "Use Custom Avatar")]'));
|
||||||
done();
|
await browser.executeScript('arguments[0].scrollIntoView(false)', button);
|
||||||
});
|
await browser.findElement(By.xpath('//label[contains(text(), "Use Custom Avatar")]')).click();
|
||||||
|
await browser.findElement(By.xpath('//input[@type="file" and @name="avatar"]')).sendKeys(path.resolve(__dirname, '../logo.png'));
|
||||||
|
await browser.findElement(By.xpath('//button[contains(text(), "Update Avatar")]')).click();
|
||||||
|
await browser.wait(until.elementLocated(By.xpath('//p[contains(text(),"Your avatar has been updated.")]')), TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
function editFile(done) {
|
async function checkAvatar() {
|
||||||
browser.get('https://' + app.fqdn + '/' + username + '/' + reponame + '/_edit/master/newfile').then(function () {
|
await browser.get(`https://${app.fqdn}/${username}`);
|
||||||
var cm = browser.findElement(by.xpath('//div[contains(@class,"CodeMirror")]'));
|
|
||||||
var text = 'yo';
|
const avatarSrc = await browser.findElement(By.xpath('//div[@id="profile-avatar"]/a/img')).getAttribute('src');
|
||||||
return browser.executeScript('arguments[0].CodeMirror.setValue("' + text + '");', cm);
|
|
||||||
}).then(function () {
|
const response = await superagent.get(avatarSrc);
|
||||||
return browser.findElement(by.xpath('//input[@name="commit_summary"]')).sendKeys('Dummy edit');
|
expect(response.statusCode).to.equal(200);
|
||||||
}).then(function () {
|
|
||||||
return browser.findElement(by.xpath('//button[contains(text(), "Commit Changes")]')).click();
|
|
||||||
}).then(function () {
|
|
||||||
waitForUrl('https://' + app.fqdn + '/' + username + '/' + reponame + '/src/master/newfile', done);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function login(done) {
|
async function login(username, password) {
|
||||||
browser.get('https://' + app.fqdn + '/user/login').then(function () {
|
await browser.get('https://' + app.fqdn + '/user/login');
|
||||||
return browser.findElement(by.id('user_name')).sendKeys(username);
|
|
||||||
}).then(function () {
|
await browser.findElement(By.id('user_name')).sendKeys(username);
|
||||||
return browser.findElement(by.id('password')).sendKeys(password);
|
await browser.findElement(By.id('password')).sendKeys(password);
|
||||||
}).then(function () {
|
await browser.findElement(By.xpath('//form[@action="/user/login"]//button')).click();
|
||||||
return browser.findElement(by.tagName('form')).submit();
|
await browser.wait(until.elementLocated(By.xpath('//img[contains(@class, "avatar")]')), TIMEOUT);
|
||||||
}).then(function () {
|
|
||||||
return browser.wait(until.elementLocated(by.linkText('Dashboard')), TIMEOUT);
|
|
||||||
}).then(function () {
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPublicKey(done) {
|
async function adminLogin() {
|
||||||
|
await login('root', 'changeme');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function logout() {
|
||||||
|
await browser.get('https://' + app.fqdn);
|
||||||
|
|
||||||
|
await browser.findElement(By.xpath('//img[contains(@class, "avatar")]')).click();
|
||||||
|
await sleep(2000);
|
||||||
|
await browser.findElement(By.xpath('//a[@data-url="/user/logout"]')).click();
|
||||||
|
await sleep(2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addPublicKey() {
|
||||||
var publicKey = fs.readFileSync(__dirname + '/id_rsa.pub', 'utf8');
|
var publicKey = fs.readFileSync(__dirname + '/id_rsa.pub', 'utf8');
|
||||||
|
|
||||||
browser.get('https://' + app.fqdn + '/user/settings/ssh').then(function () {
|
const sshPage = 'https://' + app.fqdn + '/user/settings/keys';
|
||||||
return browser.findElement(by.xpath('//div[text()="Add Key"]')).click();
|
|
||||||
}).then(function () {
|
await browser.get(sshPage);
|
||||||
return browser.findElement(by.id('ssh-key-title')).sendKeys('testkey');
|
|
||||||
}).then(function () {
|
await browser.wait(until.elementLocated(By.id('add-ssh-button')), TIMEOUT);
|
||||||
return browser.findElement(by.id('ssh-key-content')).sendKeys(publicKey.trim()); // #3480
|
await browser.findElement(By.id('add-ssh-button')).click();
|
||||||
}).then(function () {
|
await browser.findElement(By.id('ssh-key-title')).sendKeys('testkey');
|
||||||
return browser.findElement(by.xpath('//button[contains(text(), "Add Key")]')).click();
|
await browser.findElement(By.id('ssh-key-content')).sendKeys(publicKey.trim()); // #3480
|
||||||
}).then(function () {
|
var button = browser.findElement(By.xpath('//button[contains(text(), "Add Key")]'));
|
||||||
return browser.wait(until.elementLocated(by.xpath('//p[contains(text(), "added successfully!")]')), TIMEOUT);
|
await browser.executeScript('arguments[0].scrollIntoView(false)', button);
|
||||||
}).then(function () {
|
await browser.findElement(By.xpath('//button[contains(text(), "Add Key")]')).click();
|
||||||
done();
|
|
||||||
});
|
await browser.wait(until.elementLocated(By.xpath('//p[contains(text(), "has been added.")]')), TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createRepo(done) {
|
async function createRepo() {
|
||||||
browser.get('https://' + app.fqdn).then(function () {
|
var getRepoPage = await browser.get('https://' + app.fqdn + '/repo/create');
|
||||||
return browser.findElement(by.linkText('New Repository')).click();
|
|
||||||
}).then(function () {
|
await browser.findElement(By.id('repo_name')).sendKeys(reponame);
|
||||||
return browser.wait(until.elementLocated(by.xpath('//*[contains(text(), "New Repository")]')), TIMEOUT);
|
var button = browser.findElement(By.xpath('//button[contains(text(), "Create Repository")]'));
|
||||||
}).then(function () {
|
await browser.executeScript('arguments[0].scrollIntoView(true)', button);
|
||||||
return browser.findElement(by.id('repo_name')).sendKeys(reponame);
|
await browser.findElement(By.id('auto-init')).click();
|
||||||
}).then(function () {
|
await browser.findElement(By.xpath('//button[contains(text(), "Create Repository")]')).click();
|
||||||
return browser.findElement(by.id('auto-init')).click();
|
|
||||||
}).then(function () {
|
await browser.wait(function () {
|
||||||
return browser.findElement(by.xpath('//button[contains(text(), "Create Repository")]')).click();
|
return browser.getCurrentUrl().then(function (url) {
|
||||||
}).then(function () {
|
return url === 'https://' + app.fqdn + '/' + username + '/' + reponame;
|
||||||
browser.wait(function () {
|
});
|
||||||
return browser.getCurrentUrl().then(function (url) {
|
}, TIMEOUT);
|
||||||
return url === 'https://' + app.fqdn + '/' + username + '/' + reponame;
|
|
||||||
});
|
|
||||||
}, TIMEOUT);
|
|
||||||
}).then(function () {
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkCloneUrl(done) {
|
async function checkCloneUrl() {
|
||||||
browser.get('https://' + app.fqdn + '/' + username + '/' + reponame).then(function () {
|
await browser.get('https://' + app.fqdn + '/' + username + '/' + reponame);
|
||||||
return browser.findElement(by.id('repo-clone-ssh')).click();
|
await browser.findElement(By.id('repo-clone-ssh')).click();
|
||||||
}).then(function () {
|
|
||||||
return browser.findElement(by.id('repo-clone-url')).getAttribute('value');
|
var cloneUrl = await browser.findElement(By.id('repo-clone-url')).getAttribute('value');
|
||||||
}).then(function (cloneUrl) {
|
expect(cloneUrl).to.be(`ssh://git@${app.fqdn}:${SSH_PORT}/${username}/${reponame}.git`);
|
||||||
expect(cloneUrl).to.be('ssh://git@' + app.fqdn + ':29418/' + username + '/' + reponame + '.git');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function cloneRepo(done) {
|
function cloneRepo() {
|
||||||
rimraf.sync(repodir);
|
fs.rmSync(repodir, { recursive: true, force: true });
|
||||||
var env = Object.create(process.env);
|
var env = Object.create(process.env);
|
||||||
env.GIT_SSH = __dirname + '/git_ssh_wrapper.sh';
|
env.GIT_SSH = __dirname + '/git_ssh_wrapper.sh';
|
||||||
execSync('git clone ssh://git@' + app.fqdn + ':29418/' + username + '/' + reponame + '.git ' + repodir, { env: env });
|
execSync(`git clone ssh://git@${app.fqdn}:${SSH_PORT}/${username}/${reponame}.git ${repodir}`, { env: env });
|
||||||
done();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function pushFile(done) {
|
function pushFile() {
|
||||||
var env = Object.create(process.env);
|
const env = Object.create(process.env);
|
||||||
env.GIT_SSH = __dirname + '/git_ssh_wrapper.sh';
|
env.GIT_SSH = __dirname + '/git_ssh_wrapper.sh';
|
||||||
execSync('touch newfile && git add newfile && git commit -a -mx && git push ssh://git@' + app.fqdn + ':29418/' + username + '/' + reponame + ' master',
|
execSync(`touch newfile && git add newfile && git commit -a -mx && git push ssh://git@${app.fqdn}:${SSH_PORT}/${username}/${reponame} main`,
|
||||||
{ env: env, cwd: repodir });
|
{ env: env, cwd: repodir });
|
||||||
rimraf.sync('/tmp/testrepo');
|
fs.rmSync(repodir, { recursive: true, force: true });
|
||||||
done();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function fileExists() {
|
function fileExists() {
|
||||||
expect(fs.existsSync(repodir + '/newfile')).to.be(true);
|
expect(fs.existsSync(repodir + '/newfile')).to.be(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
xit('build app', function () {
|
async function sendMail() {
|
||||||
execSync('cloudron build', { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
await browser.get(`https://${app.fqdn}/admin/config`);
|
||||||
});
|
|
||||||
|
|
||||||
it('can login', function (done) {
|
var button = await browser.findElement(By.xpath('//button[@id="test-mail-btn"]'));
|
||||||
var inspect = JSON.parse(execSync('cloudron inspect'));
|
await browser.executeScript('arguments[0].scrollIntoView(true)', button);
|
||||||
|
await browser.findElement(By.xpath('//input[@name="email"]')).sendKeys('test@cloudron.io');
|
||||||
|
await browser.findElement(By.xpath('//button[@id="test-mail-btn"]')).click();
|
||||||
|
await browser.wait(until.elementLocated(By.xpath('//p[contains(text(),"A testing email has been sent to \'test@cloudron.io\'")]')), TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
superagent.post('https://' + inspect.apiEndpoint + '/api/v1/developer/login').send({
|
xit('build app', function () { execSync('cloudron build', EXEC_ARGS); });
|
||||||
username: username,
|
it('install app', function () { execSync(`cloudron install --location ${LOCATION} -p SSH_PORT=${SSH_PORT}`, EXEC_ARGS); });
|
||||||
password: password
|
|
||||||
}).end(function (error, result) {
|
|
||||||
if (error) return done(error);
|
|
||||||
if (result.statusCode !== 200) return done(new Error('Login failed with status ' + result.statusCode));
|
|
||||||
|
|
||||||
token = result.body.token;
|
|
||||||
|
|
||||||
superagent.get('https://' + inspect.apiEndpoint + '/api/v1/profile')
|
|
||||||
.query({ access_token: token }).end(function (error, result) {
|
|
||||||
if (error) return done(error);
|
|
||||||
if (result.statusCode !== 200) return done(new Error('Get profile failed with status ' + result.statusCode));
|
|
||||||
|
|
||||||
email = result.body.email;
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('install app', function () {
|
|
||||||
execSync('cloudron install --new --wait --location ' + LOCATION, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can get app information', getAppInfo);
|
it('can get app information', getAppInfo);
|
||||||
it('can get the main page', function (done) {
|
|
||||||
superagent.get('https://' + app.fqdn).end(function (error, result) {
|
|
||||||
expect(error).to.be(null);
|
|
||||||
expect(result.status).to.eql(200);
|
|
||||||
|
|
||||||
done();
|
it('can admin login', adminLogin);
|
||||||
});
|
it('can send mail', sendMail);
|
||||||
});
|
it('can logout', logout);
|
||||||
|
|
||||||
it('can login', login);
|
it('can login', login.bind(null, username, password));
|
||||||
it('can set avatar', setAvatar);
|
it('can set avatar', setAvatar);
|
||||||
it('can get avatar', checkAvatar);
|
it('can get avatar', checkAvatar);
|
||||||
|
|
||||||
@@ -243,69 +196,60 @@ describe('Application life cycle test', function () {
|
|||||||
it('can clone the url', cloneRepo);
|
it('can clone the url', cloneRepo);
|
||||||
|
|
||||||
it('can add and push a file', pushFile);
|
it('can add and push a file', pushFile);
|
||||||
it('can edit file', editFile);
|
|
||||||
|
|
||||||
it('can restart app', function (done) {
|
it('can restart app', function () { execSync('cloudron restart --app ' + app.id); });
|
||||||
execSync('cloudron restart --wait');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can clone the url', checkCloneUrl);
|
xit('can login', login.bind(null, username, password)); // no need to relogin since session persists
|
||||||
|
it('displays correct clone url', checkCloneUrl);
|
||||||
it('can clone the url', cloneRepo);
|
it('can clone the url', cloneRepo);
|
||||||
it('file exists in repo', fileExists);
|
it('file exists in repo', fileExists);
|
||||||
|
|
||||||
it('backup app', function () {
|
it('backup app', function () { execSync('cloudron backup create --app ' + app.id, EXEC_ARGS); });
|
||||||
execSync('cloudron backup create --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
it('restore app', function () { execSync('cloudron restore --app ' + app.id, EXEC_ARGS); });
|
||||||
});
|
|
||||||
|
|
||||||
it('restore app', function () {
|
|
||||||
execSync('cloudron restore --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
|
||||||
});
|
|
||||||
|
|
||||||
|
it('can login', login.bind(null, username, password));
|
||||||
it('can get avatar', checkAvatar);
|
it('can get avatar', checkAvatar);
|
||||||
it('can clone the url', cloneRepo);
|
it('can clone the url', cloneRepo);
|
||||||
it('file exists in repo', function () { expect(fs.existsSync(repodir + '/newfile')).to.be(true); });
|
it('file exists in repo', function () { expect(fs.existsSync(repodir + '/newfile')).to.be(true); });
|
||||||
|
|
||||||
it('move to different location', function () {
|
it('move to different location', async function () {
|
||||||
browser.manage().deleteAllCookies();
|
//browser.manage().deleteAllCookies(); // commented because of error "'Network.deleteCookie' wasn't found"
|
||||||
execSync('cloudron configure --wait --location ' + LOCATION + '2', { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
// ensure we don't hit NXDOMAIN in the mean time
|
||||||
var inspect = JSON.parse(execSync('cloudron inspect'));
|
await browser.get('about:blank');
|
||||||
app = inspect.apps.filter(function (a) { return a.location === LOCATION + '2'; })[0];
|
|
||||||
expect(app).to.be.an('object');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can login', login);
|
execSync('cloudron configure --location ' + LOCATION + '2 --app ' + app.id, EXEC_ARGS);
|
||||||
|
});
|
||||||
|
it('can get app information', getAppInfo);
|
||||||
|
|
||||||
|
it('can login', login.bind(null, username, password));
|
||||||
it('can get avatar', checkAvatar);
|
it('can get avatar', checkAvatar);
|
||||||
it('displays correct clone url', checkCloneUrl);
|
it('displays correct clone url', checkCloneUrl);
|
||||||
it('can clone the url', cloneRepo);
|
it('can clone the url', cloneRepo);
|
||||||
it('file exists in repo', function () { expect(fs.existsSync(repodir + '/newfile')).to.be(true); });
|
it('file exists in repo', function () { expect(fs.existsSync(repodir + '/newfile')).to.be(true); });
|
||||||
|
|
||||||
it('uninstall app', function () {
|
it('uninstall app', async function () {
|
||||||
execSync('cloudron uninstall --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
// ensure we don't hit NXDOMAIN in the mean time
|
||||||
|
await browser.get('about:blank');
|
||||||
|
execSync('cloudron uninstall --app ' + app.id, EXEC_ARGS);
|
||||||
});
|
});
|
||||||
|
|
||||||
// check if the _first_ login via email succeeds
|
// No SSO
|
||||||
it('can login via email', function (done) {
|
it('install app (no sso)', function () { execSync(`cloudron install --no-sso --location ${LOCATION} -p SSH_PORT=${SSH_PORT}`, EXEC_ARGS); });
|
||||||
execSync('cloudron install --new --wait --location ' + LOCATION, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
|
||||||
var inspect = JSON.parse(execSync('cloudron inspect'));
|
|
||||||
|
|
||||||
app = inspect.apps.filter(function (a) { return a.location === LOCATION; })[0];
|
it('can get app information', getAppInfo);
|
||||||
expect(app).to.be.an('object');
|
it('can admin login (no sso)', adminLogin);
|
||||||
|
it('can logout', logout);
|
||||||
|
|
||||||
login(function (error) {
|
it('uninstall app (no sso)', async function () {
|
||||||
if (error) return done(error);
|
await browser.get('about:blank');
|
||||||
execSync('cloudron uninstall --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
execSync('cloudron uninstall --app ' + app.id, EXEC_ARGS);
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// test update
|
// test update
|
||||||
it('can install app', function () {
|
it('can install app', function () { execSync(`cloudron install --appstore-id ${app.manifest.id} --location ${LOCATION} -p SSH_PORT=${SSH_PORT}`, EXEC_ARGS); });
|
||||||
execSync('cloudron install --new --wait --appstore-id ' + app.manifest.id + ' --location ' + LOCATION, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can get app information', getAppInfo);
|
it('can get app information', getAppInfo);
|
||||||
it('can login', login);
|
it('can login', login.bind(null, username, password));
|
||||||
it('can set avatar', setAvatar);
|
it('can set avatar', setAvatar);
|
||||||
it('can get avatar', checkAvatar);
|
it('can get avatar', checkAvatar);
|
||||||
it('can add public key', addPublicKey);
|
it('can add public key', addPublicKey);
|
||||||
@@ -313,15 +257,21 @@ describe('Application life cycle test', function () {
|
|||||||
it('can clone the url', cloneRepo);
|
it('can clone the url', cloneRepo);
|
||||||
it('can add and push a file', pushFile);
|
it('can add and push a file', pushFile);
|
||||||
|
|
||||||
it('can update', function () {
|
it('can update', function () { execSync('cloudron update --app ' + app.id, EXEC_ARGS); });
|
||||||
execSync('cloudron install --wait --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
it('can get app information', getAppInfo);
|
||||||
});
|
|
||||||
|
|
||||||
|
it('can admin login', adminLogin);
|
||||||
|
it('can send mail', sendMail);
|
||||||
|
it('can logout', logout);
|
||||||
|
|
||||||
|
it('can login', login.bind(null, username, password));
|
||||||
it('can get avatar', checkAvatar);
|
it('can get avatar', checkAvatar);
|
||||||
it('can clone the url', cloneRepo);
|
it('can clone the url', cloneRepo);
|
||||||
it('file exists in cloned repo', fileExists);
|
it('file exists in cloned repo', fileExists);
|
||||||
|
|
||||||
it('uninstall app', function () {
|
it('uninstall app', async function () {
|
||||||
execSync('cloudron uninstall --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
// ensure we don't hit NXDOMAIN in the mean time
|
||||||
|
await browser.get('about:blank');
|
||||||
|
execSync('cloudron uninstall --app ' + app.id, EXEC_ARGS);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user