Git Product home page Git Product logo

packeton's Introduction

Packeton - Private PHP package repository for vendors

Run Tests PHP Version Require Hits-of-Code Docker pulls License

Fork of Packagist. The Open Source alternative of Private Packagist for vendors, that based on Satis and Packagist.

Full documentation docs.packeton.org

Features

  • Compatible with Composer API v2, bases on Symfony 6.
  • Support update webhook for GitHub, Gitea, Bitbucket and GitLab or custom format.
  • Customers user and ACL groups and limit access by vendor and versions.
  • Composer Proxies and Mirroring.
  • Generic Packeton webhooks
  • Allow to freeze updates for the new releases after expire a customers license.
  • Mirroring for packages zip files and downloads it's from your host.
  • Credentials and Authentication http-basic config or ssh keys.
  • Support monolithic repositories, like symfony/symfony
  • Pull Request composer.lock change review.
  • OAuth2 GitHub, Bitbucket, GitLab/Gitea and Other Integrations.
  • Security Monitoring.
  • Milty sub repositories.

What was changed in this fork?

  • Disable anonymously access, registrations, spam/antispam, added ACL permissions.
  • Support MySQL, PostgresSQL or SQLite.
  • Removed HWIOBundle, Algolia, GoogleAnalytics and other not used dependencies and other metrics collectors.

Table of content

Demo

See our Administration Demo. Username/password (admin/123456)

Demo

Install and Run in Docker

You can use packeton/packeton image or GitHub container registry ghcr.io/vtsykun/packeton:latest image

docker run -d --name packeton \
    --mount type=volume,src=packeton-data,dst=/data \
    -p 8080:80 \
    packeton/packeton:latest

After container is running, you may wish to create an admin user via command packagist:user:manager

docker exec -it packeton bin/console packagist:user:manager admin --password=123456 --admin

Or build and run docker container with docker-compose:

  • docker-compose.yml Single container example, here the container runs supervisor that to start other jobs: nginx, redis, php-fpm, cron, worker. However, it does not follow the docker best-practises where 1 service must be per container. But it is very easy to use and KISS principle

  • docker-compose-split.yml - multiple containers, where 1 service per container

docker-compose build

docker-compose up -d # Run with single supervisor container 
docker-compose up -f docker-compose-split.yml -d # Or split 

Docker Environment variables

  • APP_SECRET - Must be static, used for encrypt SSH keys in database. The value is generated automatically, see .env in the data volume.
  • APP_COMPOSER_HOME - composer home, default /data/composer
  • DATABASE_URL - Database DSN, default sqlite:////data/app.db. Example for postgres "postgresql://app:[email protected]:5432/app?serverVersion=14&charset=utf8"
  • PACKAGIST_DIST_PATH - Default /data/zipball, path to storage zipped versions
  • REDIS_URL - Redis DB, default redis://localhost
  • PACKAGIST_DIST_HOST - Hostname, (auto) default use the current host header in the request.
  • TRUSTED_PROXIES - Ips for Reverse Proxy. See Symfony docs
  • TRUSTED_HOSTS - Trusted host, set if you've enabled public access and your nginx configuration uses without server_name. Otherwise, possible the DDoS attack with generated a big cache size for each host.
  • PUBLIC_ACCESS - Allow anonymous users access to read packages metadata, default: false
  • MAILER_DSN - Mailer for reset password, default disabled
  • MAILER_FROM - Mailer from

Installation

Requirements

  • PHP 8.1+
  • Redis for some functionality (favorites, download statistics, worker queue).
  • git/svn/hg depending on which repositories you want to support.
  • Supervisor to run a background job worker
  • (optional) MySQL or PostgresSQL for the main data store, default SQLite
  1. Clone the repository
  2. Install dependencies: composer install
  3. Create .env.local and copy needed environment variables into it, see docker Environment variables section
  4. Run bin/console doctrine:schema:update --force --complete to set up the DB
  5. Create admin user via console.
php bin/console packagist:user:manager username [email protected] --password=123456 --admin 
  1. (optional) If you changed the configuration files, then you need to clear the cache rm -rf var/cache/* or php bin/console cache:clear

  2. Enable cron tabs and background jobs. Enable crontab crontab -e -u www-data or use Docker friendly build-in cron demand runner.

* * * * * /var/www/packagist/bin/console okvpn:cron >> /dev/null

Example, run cron as background process without crontab. Can use with supervisor.

bin/console okvpn:cron --demand

Setup Supervisor to run worker.

sudo apt -y --no-install-recommends install supervisor

Create a new supervisor configuration.

sudo vim /etc/supervisor/conf.d/packagist.conf

Add the following lines to the file.

[program:packagist-workers]
environment =
        HOME=/var/www/
command=/var/www/packagist/bin/console packagist:run-workers --env=prod --no-debug
directory=/var/www/packagist/
process_name=%(program_name)s_%(process_num)02d
numprocs=1
autostart=true
autorestart=true
startsecs=0
redirect_stderr=true
priority=1
user=www-data
  1. IMPORTANT Make sure that web-server, cron and supervisor run under the same user, that should have an ssh key that gives it read (clone) access to your git/svn/hg repositories. If you run application under www-data you can add your ssh keys to /var/www/.ssh/

You should now be able to access the site, create a user, etc.

  1. Make a VirtualHost with DocumentRoot pointing to public/

Ssh key access and composer oauth token.

Packagist uses the Composer global config and global ssh-key to get read access to your repositories, so the supervisor worker packagist:run-workers and web-server must run under the user, that have ssh key or composer config that gives it read (clone) access to your git/svn/hg repositories. For example, if your application runs under www-data and have home directory /var/www, directory structure must be like this.

    └── /var/www/
        └── .ssh/ # ssh keys directory
            ├── config
            ├── id_rsa # main ssh key
            ├── private_key_2 # additional ssh key
            └── private_key_3

Example ssh config for multiple SSH Keys for different github account/repos, see here for details

# .ssh/config - example

Host github-oroinc
	HostName github.com
	User git
	IdentityFile /var/www/.ssh/private_key_2
	IdentitiesOnly yes

Host github-org2
	HostName github.com
	User git
	IdentityFile /var/www/.ssh/private_key_3
	IdentitiesOnly yes

If you have the error This private key is not valid inserting your ssh in admin panel is because the ssh key was generated with newer OpenSSH. New keys with OpenSSH private key format can be converted using ssh-keygen utility to the old PEM format. ssh-keygen -p -m PEM -f ~/.ssh/id_rsa

You can add GitHub/GitLab access token to auth.json of composer home dir (default APP_COMPOSER_HOME="%kernel.project_dir%/var/.composer") or use UI credentials, see here

{
    "github-oauth": {
        "github.com": "xxxxxxxxxxxxx"
    }
}

Allow connections to http

You can create config.json in the composer home (see APP_COMPOSER_HOME env var) or add this option in the UI credentials form.

{
    "secure-http": false
}

Don't use GitHub Api.

We disable usage GitHub API by default to force use ssh key or clone the repository via https as it would with any other git repository. You can enable it again with env option GITHUB_NO_API see here.

Configuration

In order to add a configuration add a file with any name to the folder config/packages/*. The config will merge with default values in priority sorted by filename.

The configuration for Docker installation is available at /data/config.yaml. Also, you can use docker volume to add config directly at path config/packages/ldap.yaml.

...
        volumes:
            - .docker:/data
            - ${PWD}/ldap.yaml:/var/www/packagist/config/packages/ldap.yaml

Where /var/www/packagist/ default ROOT for docker installation.

Full example of configuration.

packeton:
    github_no_api: '%env(bool:GITHUB_NO_API)%' # default true
    rss_max_items: 30
    archive: true

    # default false
    anonymous_access: '%env(bool:PUBLIC_ACCESS)%'

    anonymous_archive_access: '%env(bool:PUBLIC_ACCESS)%' # default false

    archive_options:
        format: zip
        basedir: '%env(resolve:PACKAGIST_DIST_PATH)%'
        endpoint: '%env(PACKAGIST_DIST_HOST)%' # default auto detect by host headers 
        include_archive_checksum: false
        prebuild_zipball: false # If true - will be created .zip package for each release (and uploaded to S3/storage). Default - build dynamically, only if requested

    # disable by default 
    jwt_authentication:
        algo: EdDSA
        private_key: '%kernel.project_dir%/var/jwt/eddsa-key.pem'
        public_key: '%kernel.project_dir%/var/jwt/eddsa-public.pem'
        passphrase: ~

    # See mirrors section
    mirrors: ~
    
    metadata:
        format: auto # Default, see about metadata.
        info_cmd_message: ~ # Bash logo, example - \u001b[37;44m#StandWith\u001b[30;43mUkraine\u001b[0m
    
    artifacts:
        # Allow uploading archives
        support_types: ['gz', 'tar', 'tgz', 'zip']
        #Allowed paths for artifact composer repo type
        allowed_paths:
            - '/data/hdd1/composer'
        # Default path to storage/(local cache for S3) of uploaded artifacts
        artifact_storage: '%composer_home_dir%/artifact_storage'

    web_protection: 
        ## Multi host protection, disable web-ui if host !== app.example.com and ips != 127.0.0.1, 10.9.1.0/24
        ## But the repo metadata will be available for all hosts and ips.
        repo_hosts: ['*', '!app.example.com'] 
        allow_ips: '127.0.0.1, 10.9.1.0/24'

Metadata format.

Packeton support metadata for Composer 1 and 2. For performance reasons, for Composer 1 uses metadata depending on the user-agent header: providers-lazy-url if ua != 1; provider-includes if ua == 1;

Format strategy UA 1 UA 2 UA is NULL
auto provider-includes metadata-url providers-lazy-url metadata-url providers-lazy-url metadata-url
only_v1 provider-includes provider-includes provider-includes
only_v2 metadata-url metadata-url metadata-url
full provider-includes metadata-url provider-includes metadata-url provider-includes metadata-url

Where UA 1 - Composer User-Agent = 1. UA 2 - Composer User-Agent = 2.

Update Webhooks

You can use GitLab, Gitea, GitHub, and Bitbucket project post-receive hook to keep your packages up to date every time you push code. More simple way use group webhooks, to prevent from being added it per each repository manually.

Provider Group webhook support Target Path
GitHub Yes https://example.org/api/github?token=
GitLab Only paid plan https://example.org/api/update-package?token=
Gitea Yes https://example.org/api/update-package?token=
Bitbucket Yes https://example.org/api/bitbucket?token=
Custom - https://example.org/api/update-package/{packnam}?token=

Bitbucket Webhooks

To enable the Bitbucket web hook, go to your BitBucket repository, open the settings and select "Webhooks" in the menu. Add a new hook. Y ou have to enter the Packagist endpoint, containing both your username and API token. Enter https://<app>/api/bitbucket?token=user:token as URL. Save your changes and you're done.

GitLab Service

To enable the GitLab service integration, go to your GitLab repository, open the Settings > Integrations page from the menu. Search for Packagist in the list of Project Services. Check the "Active" box, enter your packeton.org username and API token. Save your changes and you're done.

GitLab Group Hooks

Group webhooks will apply to all projects in a group and allow to sync all projects. To enable the Group GitLab webhook you must have the paid plan. Go to your GitLab Group > Settings > Webhooks. Enter https://<app>/api/update-package?token=user:token as URL.

GitHub Webhooks

To enable the GitHub webhook go to your GitHub repository. Click the "Settings" button, click "Webhooks". Add a new hook. Enter https://<app>/api/github?token=user:token as URL.

Manual or other hook setup

If you do not use Bitbucket or GitHub there is a generic endpoint you can call manually from a git post-receive hook or similar. You have to do a POST request to https://example.org/api/update-package?token=user:api_token with a request body looking like this:

{
  "repository": {
    "url": "PACKAGIST_PACKAGE_URL"
  }
}

It will be works with Gitea by default.

Also, you can use package name in path parameter, see ApiController

https://example.org/api/update-package/acme/packet1?token=<token>

You can do this using curl for example:

curl -XPOST -H 'content-type:application/json' 'https://example.org/api/update-package?token=user:api_token' -d' {"repository":{"url":"PACKAGIST_PACKAGE_URL"}}'

Instead of using repo url you can use directly composer package name. You have to do a POST request with a request body.

{
  "composer": {
    "package_name": "okvpn/test"
  }
}
{
  "composer": {
    "package_name": ["okvpn/test", "okvpn/pack2"]
  }
}

Custom webhook format transformer

You can create a proxy middleware to transform JSON payload to the applicable inner format. In the first you need create a new Rest Endpoint to accept external request.

Go to Settings > Webhooks and click Add webhook. Fill the form:

  • url - https://<app>/api/update-package?token=user:token
  • More options > Name restriction - #your-unique-name# (must be a valid regex)
  • Trigger > By HTTP requests to https://APP_URL/api/webhook-invoke/{name} - select checkbox
  • Payload - Write a script using twig expression to transform external request to POST request from previous example.

For example, if the input request has a format, the twig payload may look like this:

{
   "repository":{
      "slug":"vtsykun-packeton",
      "id":11,
      "name":"vtsykun-packeton",
      "scmId":"git",
      "state":"AVAILABLE",
      "links": {
          "clone": [
              {"href": "https://github.com/vtsykun/packeton.git"}
          ]
      }
   }
}
{% set repository = request.repository.links.clone[0].href %}
{% if repository is null %}
    {{ interrupt('Request does not contains repository link') }}
{% endif %}

{% set response = {
    'repository': {'url': repository },
    'packeton': {'regex': '{^(?:ssh://git@|https?://|git://|git@)?(?P<host>[a-z0-9.-]+)(?::[0-9]+/|[:/])(scm/)?(?P<path>[\\w.-]+(?:/[\\w.-]+?)+)(?:\\.git|/)?$}i'} 
} %}

{{ response|json_encode }}

See twig expression syntax for details.

Click the "Save button"

Now if you call the url https://APP_URL/api/webhook-invoke/your-unique-name?token=<user>:<token> request will be forward to https://APP_URL/api/update-package?token=user:token with converted POST payload according to your rules.

Usage and Authentication

By default, admin user have access to all repositories and able to submit packages, create users, view statistics. The customer users can only see related packages and own profile with instruction how to use api token.

To authenticate composer access to repository needs add credentials globally into auth.json, for example:

composer config --global --auth http-basic.example.org <user> <token>

API Token you can found in your Profile.

Configure this private repository in your composer.json.

{
  "repositories": [{
      "type": "composer",
      "url": "https://packeton.company.com"
  }],
  "require": {
    "company/name1": "1.0.*",
    ....
  }
}

Create admin and maintainer users.

Application Roles

  • ROLE_USER - minimal access level, these users only can read metadata only for selected packages.
  • ROLE_FULL_CUSTOMER - Can read all packages metadata.
  • ROLE_MAINTAINER - Can submit a new package and read all metadata.
  • ROLE_ADMIN - Can create a new customer users, management webhooks and credentials.

You can create a user and then promote to admin or maintainer via console using fos user bundle commands.

php bin/console packagist:user:manager username [email protected] --password=123456 --admin # create admin user
php bin/console packagist:user:manager user1 --add-role=ROLE_MAINTAINER # Add ROLE_MAINTAINER to user user1

LICENSE

MIT

packeton's People

Contributors

alcohol avatar andrewtch avatar bgaleotti avatar bmichalski avatar chh avatar cyberalien avatar dependabot[bot] avatar dumkaaa avatar igorw avatar jakefolio avatar javiereguiluz avatar julienbourdeau avatar localheinz avatar marchagen avatar miguel250 avatar mrodespin avatar mvriel avatar naderman avatar nonamepaul94 avatar pulse00 avatar rdohms avatar seldaek avatar simensen avatar soullivaneuh avatar stloyd avatar stof avatar tflori avatar vntw avatar vtsykun avatar xaav avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

packeton's Issues

Packeton is not respecting config.json (composer)

Hi there,

I've setup a Packeton instance in my local network.
When I try to add a package from a server which is on my local network too I get an error:

image

I'm aware of the risks, but since this is a test-setup in my local network this shouldn't be a problem.

According to the manual secure-http should be set to false inside config.json to enable http-connections.

https://github.com/vtsykun/packeton#ssh-key-access-and-composer-oauth-token says the .config.json should be placed inside the root-directory of the app under .composer/config.json

This is what my config.json looks like

{
    "config": {
        "secure-http": false
    }
}

Unfortunately the error remains.

Can you tell me please how to debug this error further?

New maintainer role

Hello, we're deployng Packeton for our company, and we would find really useful a new role: maintainer.
Since all of the developers in our company should be able to browse all packages or submit, edit and update new ones.
We're forking it and we're gonna try to implement it ourselves, would you be interested in a pull request?

Forcing https with docker

Hello,
How can I force the use of HTTPS protocol?
I am currently using docker and apache proxy, but the application makes HTTP calls.

The problem I have been experiencing is that when I login with HTTPS the page redirects to HTTP and remains on the login page, even though authentication was successful.

apache VirtualHost *:443

      ...

      Protocols h2 http/1.1

      ProxyRequests on
      ProxyPreserveHost On
      ProxyPass / http://127.0.0.1:8188/
      ProxyPassReverse / http://127.0.0.1:8188/

      SSLProxyEngine On
      SSLProxyVerify none
      SSLProxyCheckPeerCN off
      SSLProxyCheckPeerName off
      SSLProxyCheckPeerExpire off

      ...

Thanks and great job!

Is there any api to add user/customer?

Hello,

we are working on selling module and we are trying to provide package by composer

we are facing an issue with that, we don't have API to create user to allow to package

Download file transfer closed with 20393382 bytes remaining to read on AWS docker

Unable to download a large zip file if the application was installed by docker on Amazon Linux. This bug does not reproduce on Ubuntu/Centos 7

Environment

Docker version 18.09.9-ce
Linux 4.14.165-131.185.amzn2.x86_64

STR

  1. Install with docker using instruction
  2. Run docker exec -it -u root packagist /bin/bash to login into container
  3. Create test script into public web dir
<?php

$file = __DIR__ . '/test.zip';
$file = new \SplFileObject(__DIR__ . '/test.zip');

$headers = array (
    3 => 'Content-Type: application/zip',
    4 => 'Content-Length: '. $file->getSize(),
    9 => 'Content-Disposition: attachment; filename=test.zip',
    10 => 'HTTP/1.1 200 OK',
);

foreach ($headers as $header) {
    header($header);
}

$out = fopen('php://output', 'wb');
$fp= fopen($file->getPathname(), 'rb');

$v = stream_copy_to_stream($fp, $out, -1, 0);
file_put_contents(__DIR__ . '/debug.txt', var_export($v, true));

fclose($out);
fclose($fp);
  1. Create test.zip file
dd if=/dev/urandom of=test.zip  bs=1k  count=24000
  1. Run the command from remote host
curl -D- -o /dev/null 'http://<ip>:8088/test.php'

Actual result:

transfer closed with error

Server: nginx/1.16.1
Content-Type: application/zip
Content-Length: 20433276
Connection: keep-alive
X-Powered-By: PHP/7.3.14

  0 19.4M    0 39894    0     0  49481      0  0:06:52 --:--:--  0:06:52 49434
curl: (18) transfer closed with 20393382 bytes remaining to read

But if download file directly - all works fine.

curl -D- -o /dev/null 'http://<ip>:8088/test.zip'

System calls

accept(10, {sa_family=AF_UNIX}, [112->2]) = 4
poll([{fd=4, events=POLLIN}], 1, 5000)  = 1 ([{fd=4, revents=POLLIN}])
times({tms_utime=456, tms_stime=220, tms_cutime=2627, tms_cstime=710}) = 1719156315
read(4, "\1\1\0\1\0\10\0\0", 8)         = 8
read(4, "\0\1\0\0\0\0\0\0", 8)          = 8
read(4, "\1\4\0\1\1\367\1\0", 8)        = 8
read(4, "\17\37SCRIPT_FILENAME/var/www/packag"..., 504) = 504
read(4, "\1\4\0\1\0\0\0\0", 8)          = 8
lstat("/var/www/packagist/web/test.php", {st_mode=S_IFREG|0644, st_size=561, ...}) = 0
lstat("/var/www/packagist/web", {st_mode=S_IFDIR|0755, st_size=192, ...}) = 0
lstat("/var/www/packagist", {st_mode=S_IFDIR|0755, st_size=241, ...}) = 0
lstat("/var/www", {st_mode=S_IFDIR|0755, st_size=81, ...}) = 0
lstat("/var", {st_mode=S_IFDIR|0755, st_size=63, ...}) = 0
rt_sigaction(SIGPROF, NULL, {sa_handler=0x55f88195a430, sa_mask=~[ILL TRAP ABRT BUS FPE KILL SEGV CONT STOP TSTP TTIN TTOU SYS RTMIN RT_1 RT_2], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7efcee2e80d4}, 8) = 0
rt_sigaction(SIGHUP, NULL, {sa_handler=0x55f88195a430, sa_mask=~[ILL TRAP ABRT BUS FPE KILL SEGV CONT STOP TSTP TTIN TTOU SYS RTMIN RT_1 RT_2], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7efcee2e80d4}, 8) = 0
rt_sigaction(SIGINT, NULL, {sa_handler=0x55f88195a430, sa_mask=~[ILL TRAP ABRT BUS FPE KILL SEGV CONT STOP TSTP TTIN TTOU SYS RTMIN RT_1 RT_2], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7efcee2e80d4}, 8) = 0
rt_sigaction(SIGQUIT, NULL, {sa_handler=0x55f88195a430, sa_mask=~[ILL TRAP ABRT BUS FPE KILL SEGV CONT STOP TSTP TTIN TTOU SYS RTMIN RT_1 RT_2], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7efcee2e80d4}, 8) = 0
rt_sigaction(SIGTERM, NULL, {sa_handler=0x55f88195a430, sa_mask=~[ILL TRAP ABRT BUS FPE KILL SEGV CONT STOP TSTP TTIN TTOU SYS RTMIN RT_1 RT_2], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7efcee2e80d4}, 8) = 0
rt_sigaction(SIGUSR1, NULL, {sa_handler=0x55f88195a430, sa_mask=~[ILL TRAP ABRT BUS FPE KILL SEGV CONT STOP TSTP TTIN TTOU SYS RTMIN RT_1 RT_2], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7efcee2e80d4}, 8) = 0
rt_sigaction(SIGUSR2, NULL, {sa_handler=0x55f88195a430, sa_mask=~[ILL TRAP ABRT BUS FPE KILL SEGV CONT STOP TSTP TTIN TTOU SYS RTMIN RT_1 RT_2], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7efcee2e80d4}, 8) = 0
setitimer(ITIMER_PROF, {it_interval={tv_sec=0, tv_usec=0}, it_value={tv_sec=180, tv_usec=0}}, NULL) = 0
rt_sigaction(SIGPROF, {sa_handler=0x55f88195a430, sa_mask=~[ILL TRAP ABRT BUS FPE KILL SEGV CONT STOP TSTP TTIN TTOU SYS RTMIN RT_1 RT_2], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7efcee2e80d4}, NULL, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [PROF], NULL, 8) = 0
getcwd("/var/www/packagist", 4095)      = 19
chdir("/var/www/packagist/web")         = 0
fcntl(3, F_SETLK, {l_type=F_RDLCK, l_whence=SEEK_SET, l_start=1, l_len=1}) = 0
stat("/var/www/packagist/web/test.zip", {st_mode=S_IFREG|0644, st_size=24576000, ...}) = 0
lstat("/var/www/packagist/web/test.zip", {st_mode=S_IFREG|0644, st_size=24576000, ...}) = 0
open("/var/www/packagist/web/test.zip", O_RDONLY) = 6
fstat(6, {st_mode=S_IFREG|0644, st_size=24576000, ...}) = 0
lseek(6, 0, SEEK_CUR)                   = 0
open("/var/www/packagist/web/test.zip", O_RDONLY) = 7
fstat(7, {st_mode=S_IFREG|0644, st_size=24576000, ...}) = 0
lseek(7, 0, SEEK_CUR)                   = 0
fstat(7, {st_mode=S_IFREG|0644, st_size=24576000, ...}) = 0
fstat(7, {st_mode=S_IFREG|0644, st_size=24576000, ...}) = 0
mmap(NULL, 24576000, PROT_READ, MAP_SHARED, 7, 0) = 0x7efcdea90000
write(4, "\1\6\0\1\37\370\0\0X-Powered-By: PHP/7.3.14"..., 8192) = 8192
write(4, "\1\6\0\1\37\370\0\0\25\277\256\271#f\211N\344A\10f\351\20\253\373\312`uW\234T\26\341"..., 8192) = 8192
write(4, "\1\6\0\1\37\370\0\0b\372\208\276.\340e\356c\221$W\346Q\312\352\233\250\2036J\10\315"..., 8192) = 8192
write(4, "\1\6\0\1\37\370\0\0\234\316f\21\203\304\7\247\201%\245hj\254\341A{\331\337\277'\343(\320"..., 8192) = 8192
write(4, "\1\6\0\1\37\370\0\0\374s\236\270\336\t\0\346\215\322\26\27\306u\225\243{8\300=\343\226n\f"..., 8192) = 8192
write(4, "\1\6\0\1\37\370\0\0\301\203`\4fvn\2418&^ O5\365\246\364eW\330\261\4\250\244"..., 8192) = 8192
write(4, "\1\6\0\1\37\370\0\0\267\224\250\f\343\225p\t\247\375PC\21^W\255qN\r\267\0237J\373"..., 8192) = 8192
write(4, "\1\6\0\1\37\370\0\0\205A\240\35%!\201\32\236UM\376\246\307\322%O\246g\263\33q\16\311"..., 8192) = 8192
write(4, "\1\6\0\1\37\370\0\0\323\r\300j\"\24\204\177\346\25\203\217\340\253\230\340\214\231=\275\224N\200o"..., 8192) = 8192
write(4, "\1\6\0\1\37\370\0\0\332r\302\v\356\325]\320\\(\346\310\275S\211:uw\4\254\351\327\265\337"..., 8192) = 8192
........
........
write(4, "\1\6\0\1\37\370\0\0\245`\276s}T\214\202\352s\242\211\16=\375O\25\342\275\215@`\r\246"..., 8192) = 8192
write(4, "\1\6\0\1\37\370\0\0h\251\261A\323ZE+\217R<\371Ln\231\355.~b\253\352\364}\210"..., 8192) = 8192
write(4, "\1\6\0\1\37\370\0\0\357c\256\"y\340!\376)eQw\337\327\270\276\275\\_\33(K\241*"..., 8192) = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=92, si_uid=82} ---
chdir("/var/www/packagist")             = 0
times({tms_utime=457, tms_stime=224, tms_cutime=2627, tms_cstime=710}) = 1719156332
write(2, "\0", 1)                       = 1
write(5, "- -  22/Feb/2020:12:38:33 +0000 "..., 52) = 52
close(6)                                = 0
setitimer(ITIMER_PROF, {it_interval={tv_sec=0, tv_usec=0}, it_value={tv_sec=0, tv_usec=0}}, NULL) = 0
umask(022)                              = 022
munmap(0x7efcdea90000, 24576000)        = 0
close(7)                                = 0
fcntl(3, F_SETLK, {l_type=F_UNLCK, l_whence=SEEK_SET, l_start=0, l_len=0}) = 0
write(4, "\1\3\0\1\0\10\0\0\0\0\0\0\0\340!\376", 16) = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=92, si_uid=82} ---
shutdown(4, SHUT_WR)                    = 0
recvfrom(4, "\1\5\0\1\0\0\0\0", 8, 0, NULL, NULL) = 8
recvfrom(4, 0x7ffe73f11200, 8, 0, NULL, NULL) = -1 ECONNRESET (Connection reset by peer)
close(4)                                = 0
munmap(0x7efce0200000, 2097152)         = 0
setitimer(ITIMER_PROF, {it_interval={tv_sec=0, tv_usec=0}, it_value={tv_sec=0, tv_usec=0}}, NULL) = 0

Bitbucket webhook not working

We have installed packeton as a private package manager. Everything is working like it should, however, we cannot get the automatic updates to work.

We use a private bitbucket for our repositories (so not on bitbucket.com). Every time we add a webhook and this is fired we get a 406 error that says {"status":"error","message":"Missing payload parameter"}.

The request is being sent to: https://packeton.<company>.ext/api/bitbucket?token=<user>:<token> (where the url and username / token are obfuscated here). The payload is being sent (we can see it in bitbucket), the url is correct and the user exists and its token is valid. What is it that we are missing?

Composer repository proxy and repeater.

The main idea of this feature to allow use Packeton as mirror/proxy for other private composer repositories for example: Satis, Magento, or public repos.
The proxy must handle private aurization and work as a repeater for metadata and zip downloads.
This will avoid cloning private packages to Packeton as vcs packages and use directly external composer repositories with Packeton api token.

Zipball configuration

I've got this error:

- Installing package/name (0.1.1): Downloading (failed)    Failed to download  package/name  from dist: The "https://example.com/zipball/package/name /1ccc92dc6d3aec958cd087b57c8d6bc6e0d7c6e3.zip" file could not be downloaded (HTTP/1.1 404 Not Found)
    Now trying to download from source
  - Installing  package/name  (0.1.1): Cloning 1ccc92dc6d from cache

What should i change in config to change example.com to my domain?

Api authorization not working

Hello,

I've successfully setup packeton and everything works fine except the API authentication.
I always get an Invalid credentials error:

bash-4.4$ composer --version
Composer version 1.10.6 2020-05-06 10:28:10

composer.json

{
        "repositories": [
                {"type": "composer", "url": "https://.....com/"}
        ],
        "name": "testABC/a-test",
        "description" : "Just a test",
        "license": "GPL-2.0-or-later",
        "config": {
                "platform": {
                        "php": "7.4"
                }
        },
        "require": {
                "test/abc": "^1.0"
        }
}

composer install

bash-4.4$ composer install -vvv
Reading ./composer.json
Loading config file /.config/composer/config.json
Loading config file ./composer.json
Checked CA file /etc/ssl/certs/ca-certificates.crt: valid
Executing command (/httpdocs/web/test): git branch --no-color --no-abbrev -v
Executing command (/httpdocs/web/test): git describe --exact-match --tags
Executing command (/httpdocs/web/test): git log --pretty="%H" -n1 HEAD
Executing command (/httpdocs/web/test): hg branch
Executing command (/httpdocs/web/test): fossil branch list
Executing command (/httpdocs/web/test): fossil tag list
Executing command (/httpdocs/web/test): svn info --xml
Failed to initialize global composer: Composer could not find the config file: /.config/composer/composer.json
To initialize a project, please create a composer.json file as described in the https://getcomposer.org/ "Getting Started" section
Running 1.10.6 (2020-05-06 10:28:10) with PHP 7.4.3 on Linux / 4.9.0-12-amd64
Loading composer repositories with package information
Downloading https://........com/packages.json
    Authentication required (......com):
      Username: user1
      Password:
Using HTTP basic authentication with username "user1"
Downloading https://........com/packages.json
Downloading https://........com/packages.json
Downloading https://........com/packages.json


  [Composer\Downloader\TransportException]
  Invalid credentials for 'https://........com/packages.json', aborting.

Did something changed in the composer authentication mechanism which broke the API access in packeton?

Thanks in advance.

Improve performance when packages metadata is large.

  • Auto detect composer API user agent and disable provider-includes if composer = 2 (#76)
  • Using the redis storage to save last modified time by each packages (#76)
  • Allow switch supported composer versions Composer1, Composer2. Allow to disable metadata v2 format (#76)

Sometimes the first version of metadata format is faster than api v2 format. For example, in networks via http proxy, like tor or i2p composer can not use httpv2 to reuse connection, so 304 requests very slowly. So metadata v1 is better reuse cache due to sha256 hash identity.

Auth for mirroring proxy

Description

The ROLE_USER auth does not work for mirroring packages. The composer return everytime:

Invalid credentials for 'https://xxx:[email protected]/mirror/<>/packages.json', aborting.

The user has access over ACL group. The group has selected the allowed proxy.

Can you reproduce the bug on the Packeton demo site?

None

Database

None

Screenshots

No response

How are you running Packeton?

We are running packeton in single container mode

Question: Docker Image Release

Hello,
again my congratulations on the project.

I was wondering when a new version is scheduled to be released on dockerhub. I am looking forward to try the latest changes.
I see the demo version different from the one published on dockerhub.

Thanks again.

Customer is able to install a package which is not assigned to him

Description

I have created a customer and have not assigned him any package, still, i am able to install the package using composer require
below is a response from get customer

{
"id": 6,
"username": "customer4",
"email": "[email protected]",
"enabled": true,
"createdAt": "2023-03-10T08:11:04+00:00",
"expireAt": "2023-03-31T00:00:00+00:00",
"expiredUpdatesAt": "2023-03-31T00:00:00+00:00",
"apiToken": "###########",
"roles": [
"ROLE_USER"
],
"groups": [],
"allowedPackages": [],
"allowedProxies": [],
"isMaintainer": false,
"gravatarUrl": "https://www.gravatar.com/avatar/b5ff41c6ec6b2f14d8f7c275617767de?d=identicon",
"fullAccess": false
}

Can you reproduce the bug on the Packeton demo site?

Yes

Database

SQLite

Screenshots

image

How are you running Packeton?

Yes

Packages don't get crawled

Hi,

I've found out that packages can't be crawled. The Update button keep loading:

Is there a way to fix this?

Thanks

v2.0 Migration issue

We tried the migration from the latest v1 to v2.0 and it fails.

  • we use single docker-container with docker-compose
  • (In prior version, we used env-variables in docker-compose to specify the mysql params)
  • changed docker-compose to new image, change volume path
  • restart recreated the container with new sqlite database.
  • changes in host .env file (linked to .env.local in container) has no effect
  • changes in .env in container has no effect

Seems, that the .env files in the single container images are ignored.

Time modify time and create are 1980-01-01

when i download the package , the datetime of file are Jan 1 1980

-rw-rw-r-- 1 user user      810 Jan  1  1980 composer.json
drwxrwxr-x 2 user user     4096 Apr 17 21:29 configurations
drwxrwxr-x 2 user user     4096 Apr 17 21:29 docs
-rw-rw-r-- 1 user user      157 Jan  1  1980 manifest.json
-rw-rw-r-- 1 user user       45 Jan  1  1980 README.md
drwxrwxr-x 8 user user     4096 Apr 17 21:29 resources
drwxrwxr-x 8 user user     4096 Apr 17 21:29 src
drwxrwxr-x 2 user user     4096 Apr 17 21:29 tests

I build use source code and deploy on centos.

Composer > 2.1.4

Can composer 2.0 be used so that hopefully versions like this: 1.2.3-dev will work?

Demo is offline

The demo mentioned in the readme file appears to be offline. I wanted to check it before installing...

Packages dist 404 if the zipball has not been previously downloaded.

In my use case, users shouldn't/can't have access to the original git repo, but may download specific dists.

And the issue occurs when targeting a branch commit like master or version branch like 1.0.x, where the lock file references a previous commit, but the zipball was never downloaded and stored in order to do a lookup against.

The current Distmanager::download method only attempts to download if the hash matches a current release, whereas I think there should probably be logic in place to ensure that old zipballs hashes may be downloaded without having to update the lock file.

This results in composer install returning the following:

- Installing vendor/package (1.0.x-dev 4b825dc6): Downloading (connecting...)                           Downloading (failed)                  Failed to download vendor/package from dist: The "https://packagist.vendor.co.uk/zipball/vendor/package/4b825dc642cb6eb9a060e54bf8d69288fbee4904.zip" file could not be downloaded (HTTP/1.1 404 Not Found)
  Now trying to download from source
- Installing vendor/package (1.0.x-dev 4b825dc6): Cloning 4b825dc642c

[RuntimeException]
Failed to execute git clone --no-checkout 'ssh://[email protected]:22/vendor/project-name.git' 'vendor/package' && cd 'vendor/package' && git remote add composer 'ssh://[email protected]:22/vendor/project-name.git' && git fetch composer && git remote set-url origin 'ssh://[email protected]:22/vendor/project-name.git' && git remote set-url composer 'ssh://[email protected]:22/vendor/project-name.git'

Cloning into 'vendor/package'...
Host key verification failed.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

Block storage

Hi,
is there way to use block storage(AWS S3 like/compatible) to store zipballs? It's mandatory for FaaS deployment where persistent storage is unavailable like DigitalOcean App Platform.

Disable zipball creation for packages

Description

Hi @vtsykun and first of all, thanks for this great project!

We would like to use Packeton to manage our composer packages, but we do not need/want the zipball feature.
Instead the applications should clone the packages directly from our GitLab server, ensuring authentication with the respective deploy keys.

After having a look at your documentation and code, we thought that the configuration option archive should allow such behavior.

So we tried to set the configuration option archive to false. However, now the Packeton application throws a RuntimeException:

[Symfony\Component\DependencyInjection\Exception\RuntimeException]                                               
  You have requested a non-existent parameter "packeton_archive_opts". Did you mean this: "packeton_dumper_opts"?

This exception can be mitigated by changing Packeton\DependencyInjection\PacketonExtension to initialize the packeton_archive_opts:

        [...]

        if (true === $config['archive']) {
            $container->setParameter('packeton_archive_opts', $config['archive_options'] ?? []);
        } else {
            $container->setParameter('packeton_archive_opts', []);
        }

        [...]

Now another exception is thrown:

  [Symfony\Component\DependencyInjection\Exception\EnvParameterException]                                    
  Environment variables "PACKAGIST_DIST_HOST" are never used. Please, check your container's configuration.

We tried to fix the issues, but could not find a satisfactory solution yet.

If we add --prefer-source to the composer install commands, we get the desired behavior for our internal packages.
However, we'd like to avoid changing all scripts where composer packages are installed. Furthermore, this is also applied to
external packages and therefore slows down the installation from packagist.org a lot.

How can we best achieve our goal (downloads only directly from the configured Git sources)?

Thank you very much, best regards

Can you reproduce the bug on the Packeton demo site?

N/A

Database

SQLite

Screenshots

No response

How are you running Packeton?

Official docker image

How to keep database persitance?

Hello,

we are going to use this service into production and I see we are using docker thing, if we do docker-compose down/stop, that time all data of db will truncate

That time we will face big issue, how you guys doing on live production env?

Are you guys using EC2 any service for that ? and use that configuration into docker?

400 Bad Request at first run

Hi,

I installed successfully packeton from sources but when I try to access the page (first time) on my browser, I got this error:

Oops! An Error Occurred
The server returned a "400 Bad Request".
Something is broken. Please let us know what you were doing when this error occurred. We will fix it as soon as possible. Sorry for any inconvenience caused.

I've also noticed that what is causing the bad request is the xhr request to / and /favicon.ico.

How can I fix it?

Thanks

Feature Request: Submit API

We are in the process of moving from Satis to Packeton.
To add new packages from our bitbucket we made a script to scan bitbucket for composer modules and add them to satis.

It would be nice to be able to handle this nicely with an endpoint in Packeton.
Or is this already possible with an existing endpoint?

Of course it's also possible to just add them to the database (which is probably what i'll do)
But an endpoint is a lot nicer and could provide extra validation.

Question: OAuth Login

Hi @vtsykun, i've cheked the demo dashboard and the settings. I want to ask if there's features to integrate OAuth login like Google/Gitlab/Github?

Thank you!

install repository by fork and then docker-compose up

Hello,

I m trying to edit something so i clone repo and then run docker-compose up and i getting below issue
2023-04-17 08:12:03,909 INFO success: pkg-workers_00 entered RUNNING state, process has stayed up for > than 0 seconds (startsecs)
2023-04-17T08:12:03.955689750Z 08:12:03 NOTICE [app] Worker started successfully
2023-04-17T08:12:04.957009739Z 2023-04-17 08:12:04,956 INFO success: redis entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2023-04-17T08:12:04.958751932Z 2023-04-17 08:12:04,958 INFO spawned: 'nginx' with pid 70
2023-04-17T08:12:04.959034428Z 2023-04-17 08:12:04,958 INFO success: php entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2023-04-17T08:12:04.959051414Z 2023-04-17 08:12:04,958 INFO success: cron entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2023-04-17T08:12:04.965197677Z 2023-04-17 08:12:04,965 INFO exited: nginx (exit status 1; not expected)
2023-04-17T08:12:06.971430290Z 2023-04-17 08:12:06,970 INFO spawned: 'nginx' with pid 71
2023-04-17T08:12:06.981021646Z 2023-04-17 08:12:06,980 INFO exited: nginx (exit status 1; not expected)
2023-04-17T08:12:09.987626268Z 2023-04-17 08:12:09,987 INFO spawned: 'nginx' with pid 72
2023-04-17T08:12:09.994622533Z 2023-04-17 08:12:09,994 INFO exited: nginx (exit status 1; not expected)
2023-04-17T08:12:10.996247261Z 2023-04-17 08:12:10,995 INFO gave up: nginx entered FATAL state, too many start retries too quickly

Issue is DB Creation while Installation

PreConditions

  1. MySQL 8.0.3
  2. PHP 8.1.14

Steps To Reproduce

  1. Cloned this Repo https://github.com/vtsykun/packeton
  2. I am Following the Steps and i am at Step 4

Expected Result
Installation should complete

Actual Result

! [CAUTION] This operation should not be executed in a production environment!

Creating database schema...

05:26:48 CRITICAL [console] Error thrown while running command "doctrine:schema:create". Message: "Schema-Tool failed with Error 'An exception occurred while executing a query: SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'package_version' already exists' while executing DDL: CREATE TABLE package_version (id INT AUTO_INCREMENT NOT NULL, package_id INT DEFAULT NULL, name VARCHAR(255) NOT NULL, description LONGTEXT DEFAULT NULL, type VARCHAR(255) DEFAULT NULL, targetdir VARCHAR(255) DEFAULT NULL, extra LONGTEXT DEFAULT NULL COMMENT '(DC2Type:array)', homepage VARCHAR(255) DEFAULT NULL, version VARCHAR(255) NOT NULL, normalizedversion VARCHAR(191) NOT NULL, development TINYINT(1) NOT NULL, license LONGTEXT DEFAULT NULL, source LONGTEXT DEFAULT NULL, dist LONGTEXT DEFAULT NULL, autoload LONGTEXT DEFAULT NULL, binaries LONGTEXT DEFAULT NULL, includepaths LONGTEXT DEFAULT NULL, support LONGTEXT DEFAULT NULL, createdat DATETIME NOT NULL, softdeletedat DATETIME DEFAULT NULL, updatedat DATETIME NOT NULL, releasedat DATETIME DEFAULT NULL, INDEX IDX_3047B64FF44CABFF (package_id), INDEX release_idx (releasedAt), INDEX is_devel_idx (development), UNIQUE INDEX pkg_ver_idx (package_id, normalizedVersion), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB" ["exception" => Doctrine\ORM\Tools\ToolsException^ { …},"command" => "doctrine:schema:create","message" => "Schema-Tool failed with Error 'An exception occurred while executing a query: SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'package_version' already exists' while executing DDL: CREATE TABLE package_version (id INT AUTO_INCREMENT NOT NULL, package_id INT DEFAULT NULL, name VARCHAR(255) NOT NULL, description LONGTEXT DEFAULT NULL, type VARCHAR(255) DEFAULT NULL, targetdir VARCHAR(255) DEFAULT NULL, extra LONGTEXT DEFAULT NULL COMMENT '(DC2Type:array)', homepage VARCHAR(255) DEFAULT NULL, version VARCHAR(255) NOT NULL, normalizedversion VARCHAR(191) NOT NULL, development TINYINT(1) NOT NULL, license LONGTEXT DEFAULT NULL, source LONGTEXT DEFAULT NULL, dist LONGTEXT DEFAULT NULL, autoload LONGTEXT DEFAULT NULL, binaries LONGTEXT DEFAULT NULL, includepaths LONGTEXT DEFAULT NULL, support LONGTEXT DEFAULT NULL, createdat DATETIME NOT NULL, softdeletedat DATETIME DEFAULT NULL, updatedat DATETIME NOT NULL, releasedat DATETIME DEFAULT NULL, INDEX IDX_3047B64FF44CABFF (package_id), INDEX release_idx (releasedAt), INDEX is_devel_idx (development), UNIQUE INDEX pkg_ver_idx (package_id, normalizedVersion), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB"]

Allow patching composer proxy metadata from UI

When some old package is no longer maintained, developers have to fork to fix it to support new versions of the deps libs. Sometimes only need to fix the require section in the composer.json, but the code works without errors. To prevent a forking only for patch composer.json, Packeton can provide way to edit composer proxy metadata in UI.

An example of such a case
robotjoosen/cron-bundle@2703704

artifacts

Hi,

great repository. One question.
How can you use artifacts in this packagist?

Unauthenticated package metadata access

Thanks for your great work of continuing the open-source packagist app. Is there a way to allow package metadata read access without authentication (for all or for specific packages)?

Improve perf of creating a zip archive

Currently composer zip archive manager make an unnecessary repo mirroring to create a zip archive. It may takes 20-60 sec due to compress/decompress all objects

git clone --no-checkout '/data/composer/cache/vcs/https---github.com-oroinc-platform.git/' '/tmp/composer_archive641127b9db929' --dissociate --reference '/data/composer/cache/vcs/https---github.com-oroinc-platform.git/' && \
cd '/tmp/composer_archive641127b9db929' && \
git remote set-url origin -- 'https://github.com/oroinc/platform.git' && \
git remote add composer -- 'https://github.com/oroinc/platform.git

But it can easy replaced with the archive command. it works 100 times faster

git archive v5.4.21:src/Symfony/Component/Finder --format=zip -o /tmp/finder.zip

Status of the project

What is the status of the project? There are a few open pull requests and there has been no activity for a long time.

No way to delete credentials

Description

Hello,

While testing packeton to see if it would work for my requirements, I first added a composer auth.conf to the "My Credentials" to testing.

After that, I added a new SSH based credentials and wanted to delete the other record of auth.conf, but it doesnt seem to be any way to delete them.

Can it be done directly on the database? Or is there any other way that im missing?

Can you reproduce the bug on the Packeton demo site?

Yes

Database

SQLite

Screenshots

No response

How are you running Packeton?

Docker

Composer.json examples?

Hi.

Read the docs and didn't understand how to use it and install private packages, could you please provide any example for composer.json file?

Invalid credentials with packagist and LDAP

Hello,
I have configured the project with two authentication providers: packagist and LDAP.

The LDAP provider works, but when I login with a local user (packagist) I get this message: "Invalid credentials."

security:                
    providers:
        users_ldap:
            ldap:
                service: Symfony\Component\Ldap\Ldap
                .....

        all_users:
            chain:
                providers: ['packagist','users_ldap'] # <- Load user/roles form default packagist and if not found - use ldap user

It seems that the local user is being ignored!

Thanks and great job!

I try to edit ngix file and then i m using docker-compose-prod.yml but not working

Hello,

I try to set custom domain into ngix file so i need to use docker-compose-prod.yml
but when i use docker-compose-prod.yml, it is not working

Version in "./docker-compose-prod.yml" is unsupported. You might be seeing this error because you're using the wrong Compose file version. Either specify a supported version (e.g "2.2" or "3.3") and place your service definitions under the services key, or omit the version key and place your service definitions at the root of the file to use version 1.
For more on the Compose file format versions, see https://docs.docker.com/compose/compose-file/

My docker version : Docker version 20.10.18, build b40c2f6

Read only api token

Allow to generate api token with restriction, for example to use only in webhooks or use in CI to prevent write operation on the packages metadata for mirrors.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.