PROJET AUTOBLOG


Sam & Max: Python, Django, Git et du cul

Site original : Sam & Max: Python, Django, Git et du cul

⇐ retour index

Mise à jour

Mise à jour de la base de données, veuillez patienter...

Le bulletin sécu : https pour 0bin et leak de mots de passe 3   Recently updated !

dimanche 10 janvier 2016 à 13:42

Quand letsencrypt est passé live, on m’a gentiment signalé qu’on avait plus d’excuses pour faire tourner 0bin en clair.

Bon, soit.

J’ai mis en place ça hier à titre de test : https://0bin.net/.

Pour le moment je vais pas faire de redirection car j’attends de voir si le truc tient.

La bonne nouvelle, c’est que comme l’installation est juste nginx + zerobin, il n’y a pas eut grand chose à faire : lancer un script, le laisser nous identifier et installer les dependances pour qu’il génère le certificat et faire pointer le dit certificat par nginx.

La moins bonne nouvelle c’est que notre archi pour sametmax.com et indexerror.net est basé sur client => varnish => nginx => worker => site.

Il faut donc mettre le certif au niveau de varnish.

Mais comme vous vous en doutez bien, il fallait que ça couille : support de https est un truc récent sur varnish et notre version ne le supporte pas. Donc il reste à :

Oh, du boulot en plus, je ne m’y attendais tellement pas…

Merci à tous ceux qui ont proposé et fourni de l’aide néanmoins. C’est cool d’avoir du soutien parmi ses lecteurs.

Pendant ce temps, et ça n’a rien à voir, un lecteur s’est amusé à brute forcer des hashs de mots de passe qu’on avait leakés connement et a trouvé celui de max au bout de quelques jours. Il nous a gentiment envoyé le résultat de ses recherches par mail. Ce n’est pas ironique, hein. J’apprécie que quand quelqu’un trouve que tu es à poil il te le fasse savoir avec précision et honnêteté.

Du coup va falloir aussi changer tous les mots de passe du blog et de indexerror.

Comme ce n’est pas une question de sécurité nationale, je ne suis pas en mode bersek à vouloir faire ça dans la minute, mais sachez-le : changez vos mots de passe à l’occasion. Personne ne va violer votre sœur demain si vous ne le faites pas, mais mieux vaut prévenir que guérir.

Oh, du boulot en plus, je ne m’y attendais tellement pas…

Desactiver la validation des mots de passe en mode DEBUG sous Django

vendredi 8 janvier 2016 à 11:29

Django 1.9 rajoute la validation de “sécurité” des mots de passe comme corde à son arc.

Personnellement je trouve ça naze.

Je suis pour permettre aux utilisateurs de mettre le password qu’ils veulent, même tout pourri. De toute façon les gens qui ne font pas attention à leur sécurité ne vont jamais se souvenir du mot de passe compliqué et faire un « j’ai oublié mon mot de passe » à chaque fois.

Pire, la complexité ajoutée va faire fuir les nouveaux utilisateurs qui ne vont pas vouloir se faire chier à remplir le formulaire. Ou alors ils vont faire « login with facebook ».

Mais le plus naze dans tout ça c’est que la validation est tout ou rien : on peut pas mettre de la validation juste pour les comptes admin par exemple. Ce qui aurait du sens.

Alors, oui à la mise en oeuvre d’un indicateur de force de mot de passe, mais pas un refus catégorique de s’inscrire comme le système actuel le fait.

Dans tous les cas, vous voudrez au moins le désactiver en mode DEBUG car devoir taper un mot de passe compliqué en dev sur votre machine en local pour accéder à une base de données sqlite de test, c’est relou.

Car oui, ./manage.py createsuperuser refuse votre password si il n’est pas “sécurisé” par défaut. En prod, ça a du sens, mais quand je veux tester une merde sur mon laptop, “admin/admin” est généralement ce je veux.

Donc:

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        'OPTIONS': {
            'min_length': 9,
        }
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]
 
if DEBUG:
    AUTH_PASSWORD_VALIDATORS = []

Enfin, franchement, un validateur de mot de passe basé sur la présence de chiffres. Sérieux ? On a des validateurs basés sur une enthrophie générale depuis longtemps.

Le don du mois : Tor 5

jeudi 7 janvier 2016 à 10:57

Comme chaque mois, je fais un petit don à une entité et je fais sa pub. Premier don de 2016 : Tor, le logiciel le logiciel d’anonymisation de connexion Internet.

Je l’utilise pourtant peu. De temps en temps, je reinstalle tout le bordel, et je regarde où ça en est. Parfois, je fais un bot qui a besoin de plus d’IP et je le plug temporairement sur Tor. Mais ce n’est pas un usage régulier.

Pourtant, philosophiquement, je trouve que sa mission est de la plus haute importance : nous accumulons de l’expérience sur la mise en place d’un Internet plus démocratique, plus ouvert, moins centralisé, plus humain.

Or Internet est dévenu le cerveau connectant l’humanité entière, et il faudra bien cela, et beaucoup d’autres choses, pour s’assurer que les pensées de tous s’y reflètent, et pas juste celles d’une minorité.

Pour cela, je soutiens le développement de Tor. Je pense que ses jours sont pourtant comptés, mais sa simple existence a été primordiale à la santé d’Internet.

50 euros, en bitcoin, pour ce don.

Pourquoi utiliser un mécanisme d’exceptions ?

mercredi 6 janvier 2016 à 01:17

L’article ne vient pas de nulle part. En fait j’ai du dans la même journée répondre sur le subreddit Python a cette question et à un lecteur par email, alors je me suis dis qu’il serait bon de faire le point ici.

Avant de lire l’article, assurez-vous de bien avoir compris la gestion des erreurs en Python.

La réponse simple, courte, et définitive

“Pourquoi utiliser un mécanisme d’exceptions ?”

Parce que c’est la manière de faire du langage que vous utilisez.

Si vous êtes dans un langage qui utilise des codes de retour comme C, alors gérez les erreurs avec des codes de retour. Si vous avez du pattern matching comme en Rust, utilisez le pattern matching. Si vous avez des exceptions comme en Java, utilisez les exceptions. Si vous avez des guards comme en swift, vous utilisez des guards.

Je crois que vous avez pigé.

Ceci est la règle, qui est complètement indépendante de la qualité du système de gestion des erreurs : codez dans le style approprié pour le langage et n’essayez pas de bricoler votre solution perso dans votre coin. Si ça vous fait chier, changez de langage. Mais ne faites pas du pseudo-Go en Erlang, ça n’a pas de sens, et ça va souler tous vos collègues, en plus de diminuer l’intégration avec l’écosystème de la techno.

En Python, les erreurs (et même plus) sont gérées via un mécanisme à base d’exceptions, et c’est donc ce qu’il faut utiliser.

Maintenant, un mécanisme de gestion d’erreurs est vraiment une question de gout. Il n’y en a pas de parfait, mais il peut être intéressant de connaitre les points forts de celui qu’utilise Python.

Quels sont donc les points forts d’un mécanisme à base d’exceptions ?

Cela évite les races conditions

En informatique, dès qu’un système peut faire plusieurs choses à la fois, plusieurs choses peuvent arriver simultanément et créer ce qu’on appelle une race condition.

Par exemple, si je fais ceci:

# on vérifie que le fichier existe avant de l'ouvrir
if os.path.isfile('monfichier'): 
    with open('monfichier') as f:
        print(f.read())
else:
    print('pouet')

Entre la première ligne et la seconde ligne s’écoule un temps très court pendant lequel un autre processus peut supprimer le fichier et faire planter mon programme.

En utilisant la philosophie “il est plus facile de demander pardon que la permission”, on évite ce problème:

try:
    # on s'en bat les couilles, on essaye
    # de l'ouvrir à sec
    with open('monfichier') as f:
        print(f.read())
except OSError:
    print('pouet')

Dans ce cas on tente d’ouvrir le fichier de toute façon, et si l’ouverture déclenche une erreur, alors on la gère. Pas de race condition.

Finally et with pour les opérations de nettoyage

En ouvrant mon fichier, je dois m’assurer de le fermer après. Mais je peux avoir une erreur à l’ouverture du fichier, ou pendant sa lecture, qui fasse planter mon programme et que je n’avais pas prévu.

Comme les exceptions remontent file d’appel, on peut les attraper à plusieurs niveaux. Grave à finally (et with qui enrobe finally), on peut donc très élégamment s’assurer que les opérations de nettoyage sont lancées automatiquement, même si tout pête:

# ouvrir un fichier avec with garantit sa fermeture
with open('monfichier') as f:
    print(f.read())

Les exceptions sont très explicites

Des mécanismes comme le pattern matching ou le retour de codes sont génériques, et peuvent être utilisés pour à peu près tout.

Les exceptions, à l’image des guards, ont un champ d’usage plus restreint, et quand on en voit, on sait donc généralement à quoi s’en tenir. Cela facilite la lecture en diagonale du code.

Les exceptions décrivent une hiérarchie d’erreurs

Ceci permet non seulement de choisir de gérer plusieurs erreurs d’un coup, ou alors séparément, mais également de documenter par le type quel est le problème. Une fois qu’on connait les exceptions les plus courantes en Python (ValueError, OSError, KeyError, TypeError, etc.), on identifie vite l’idée générale d’un message d’erreur ou d’un code attrapant une erreur.

Comme peut créer ses propres types d’exceptions, on peut permettre le ciblage des erreurs d’une lib en particulier, ou d’un sous ensemble d’une lib ou d’une opération. Et c’est aussi une forme de documentation par le code.

Tout cela autorise une fine granularité sur ce qu’on veut gérer ou pas : tout d’un coup, au cas par cas, seulement sur une partie du code, etc.

Les exceptions bubblent

Sous ce terme barbare se cache le fait que les exceptions se déclenchent localement dans un bloc de code, et l’interrompe, mais ne font pas planter le programme tout de suite. À la place, l’exception monte d’un niveau dans la file d’appels, et casse tout, puis remonte d’un cran, et casse tout, et ainsi de suite, jusqu’en haut.

Ce mécanisme permet de choisir exactement où on veut arrêter l’exception, et ce que l’on souhaite qu’elle puisse interrompre. Cela laisse le choix de gérer des erreurs de manière macroscopique ou microscopique.

Par exemple, si j’utilise un try en dehors d’une boucle :

print('start')
try:
    for x in range(0, 10):
        print(1 / (x - 2))
except ZeroDivisionError:
    pass
 
print('fin')
## Affiche :
## start
## -0.5
## -1.0
## fin

Et un dans une boucle :

print('start')
for x in range(0, 10):
    try:
        print(1 / x)
    except ZeroDivisionError:
        print('ERROR !')
    else:
        print("Pas d'erreur :)")
    finally:
        print('TOUJOURS')
print('fin')
## Affiche:
## start
## ERROR !
## TOUJOURS
## 1.0
## Pas d'erreur :)
## TOUJOURS
## 0.5
## Pas d'erreur :)
## TOUJOURS
## 0.3333333333333333
## Pas d'erreur :)
## TOUJOURS
## 0.25
## Pas d'erreur :)
## TOUJOURS
## 0.2
## Pas d'erreur :)
## TOUJOURS
## 0.16666666666666666
## Pas d'erreur :)
## TOUJOURS
## 0.14285714285714285
## Pas d'erreur :)
## TOUJOURS
## 0.125
## Pas d'erreur :)
## TOUJOURS
## 0.1111111111111111
## Pas d'erreur :)
## TOUJOURS
## fin

J’obtiens un résultat radicalement différent. On peut choisir facilement l’étendue de la progragation de l’erreur.

Les exceptions ont des données attachées

Les exceptions sont des objets riches, qui viennent avec un message d’erreur, un contexte qui permet de générer une stack trace, et parfois des attributs en plus comme le code d’erreur fourni par l’OS.

C’est un point d’entrée capable de concentrer en un seul endroit tout ce dont on a besoin pour le debug.

Pas cher mon fils

En Python, les exceptions sont particulièrement peu couteuses à utiliser. En fait, Python les utilise pour le contrôle de flux (StopIteration, GeneratorExit, etc) donc elles sont au coeur du fonctionnement du langage, et pas juste pour pour les erreurs.

Faire un try/except n’a pas le coup qu’on a en Java ni en terme de performance du code, ni en terme de verbosité car il n’y a pas de throw à déclarer.

Le truc le plus ennuyeux, c’est bien entendu de trouver le nom de l’exception qu’on veut gérer et comment l’importer. Afin d’éviter cette chose affreuse:

    try:
        meh()
    except: # YOLO
        print("Il s'est passé un truc, mais je sais pas quoi")

Il y a à peine quelques heures j’étais avec un client qui avait des utilisateurs se plaignant que le système ne marchait pas sans vraiment pouvoir diagnostiquer pourquoi.

Vous voyez, pas besoin d’inventer, j’ai les exemples qui me tombent tout cru dans le bec.

Voici ce qu’il avait, en prod :

# je vous pseudo code, mais c'est l'idée
def get_dbs():
    try:
        # connection, listing, filtrage, casting
        # nahhh, que pourrait-il arriver de grave ?
        con = Connect()
        dbs = con.get_databases()
        dbs = fitler_system_db(dbs)
        return tuple(dbs)
    except: # double combo: catch all ET silence
        return ()

Oui, j’ai bien dis en prod. La base de données gère des listings de médecins. Ouch.

Le code utilisant cette fonction faisait (avant que j’arrive avec mon fouet de zorro et corrige tout ce bordel):

dbs = get_dbs()
if not dbs:
    display_error("Mongo ne tourne pas, ou la connection a échoué, ou aucune table n'est créé")

Vous imaginez comme l’utilisateur final pouvait facilement décrire son problème… Ouai alors soit t’as pas un truc, soit le truc marche pas, soit tu te sers par du truc. Ouai ça couvre à peut prêt l’ensemble des erreurs possibles sur tout système, comme ça on peut pas avoir fondamentalement tort.

Retour sur la pénurie de devs 3   Recently updated !

mardi 29 décembre 2015 à 13:24

Rien qu’autour de moi, on cherche pas loin de 50 devs joomla

Un de mes amis m’a rapporté cette discussion qu’il a eue avec un de ses contacts sur Nantes. Nantes n’est pas une grande ville. Et joomla est un CMS parmi d’autres. Par ailleurs, les CMS ce sont qu’une techno Web parmi d’autre. Et la prog Web n’est qu’une sorte de prog parmi d’autres.

Or je vous rappelle ce qu’on m’avait déjà sorti:

Quand on trouve un profil qui maitrise toutes les technos de notre stack, on lui sort le tapis rouge. C’est juste improbable.

Un collègue à moi, qui me disait il y a 2 ans autour d’un verre que son process de recrutement le minait.

Si tu viens ici je te trouve un poste à 220k.

Un client américain de longue date qui me recrute en remote parce que « c’est moins cher » et qui me confiait les tarifs pour mon profil étaient aberrant chez lui.

Le fait est qu’on a déjà du mal à trouver de la main-d’œuvre bien qualifiée maintenant.

Il y a plusieurs raisons à cela.

D’abord, il y a un nombre limité de devs, et une explosion du nombre de technos. Ces technos se sont, dans la dernière décennie, organisées en stacks complexes. Elles sont accumulées des process et des couches d’abstraction, qui évoluent rapidement pour répondre à la mutation des usages : mobile, streaming, temps réel, offline-mode, synchronisation….

La virtualisation, le cloud, les pré-processeurs, la variété des plateformes, le big data, etc. C’est à n’en plus finir.

Une personne ne peut pas tout savoir, et il peut être productif uniquement dans un nombre limité de domaines, nombre dont la taille en — proportion au reste du monde — se réduit année après année.

Les attentes des gens ayant évoluées, faire un service web compétitif aujourd’hui demande des compétences côté client et serveur, du design et la compréhension du mobile, ne serait-ce que pour un proto tout pourri. Et ça c’est que pour le Web. N’oubliez pas l’embarqué, le sysadmin, l’analyse de données, l’exploration scientifique, le jeu vidéo, les systèmes d’information internes, les systèmes métier et tout le bordel.

Bref, il faut du monde. Du monde compétent. Ce monde est limité, et la demande augmente de par la complexification de nos outils et contraintes, comme on vient de le voir. Mais aussi par la demande technologique qui grimpe.

Car aujourd’hui nous avons des ordinateurs partout. Un dans la poche, un dans la voiture, un dans la télé et certains essayent d’en foutre dans les chaussures et le frigo. La fiche de paie, l’ordonnance du médecin, la facture de carrefour et l’avis d’imposition sont tous traités par informatique.

Ceci ne va pas ralentir. Même si on ne se rajoutait pas de nouveaux usages, et on va le faire, on a 3 milliards d’asiastiques qui sont en plein boom technologique.

Et là vous allez me dire que c’est justement l’occasion de faire du offshore pour répondre à la demande.

Mais ça ne marche pas.

J’ai suivi l’expérimentation de la sous-traitance à l’étranger des années post-bulle. A l’époque, j’ai entendu un décideur dire :

on peut très prendre un Indien pour pisser du code.

J’ai aussi vu tous ces projets se planter. Une fois, un simple proto Web couter 140 000 euros pour au final n’avoir AUCUNE fonctionnalité. Véridique. 140 boulasses.

Ce n’est pas qu’on ne trouve pas les compétences adéquates hors de nos contrées. Au contraire. Mais il y a des tas de facteurs propres à notre industrie qui rendent l’exercice de la délégation délicate, et ça ferait un excellent article, mais je ne vais pas les exposer ici.

L’important c’est de noter qu’on en revient. Les devs indiens vont participer à l’essor de l’informatique de l’Inde. Les devs chinois à celui de la Chine. Et ils auront les mêmes problématiques que nous à différentes échelles et sous d’autres visages. Mais le croisement des effluves sera limité.

En revanche la globalisation va faire que leur expansion va, par effet de bord, augmenter notre activité informatique en plus de nos propres causes de croissance. On va avoir besoin de plus de devs.

Toujours plus, encore plus.

Des devs de plus en plus spécialisés pour des archis de plus en plus complexes.

Je ris quand les gens disent que les nouveaux venus ne sont pas « des vrais programmeurs ». Moi je devais faire attention au nombre de cycle CPU, aujourd’hui les gens rachètent des serveurs plutôt que d’économiser de la mémoire, etc.

Ouai, ouai, pépé, tu faisais de l’assembleur, c’est viril.

Mais le gamin de 20 ans qui arrive sur le marché, on lui colle entre les pates une app react native en JSX qui une fois transpilée par babel + gulp va se faire valider dans un market pour s’installer dans une sandbox sur des terminaux hétérogènes où elle va taper à travers un réseau wifi/4G intermittent dans une API REST sur des serveurs distants organisés en microservices Django + dockers déployés sur du cloud AWS.

Le seul point commun avec les deux époques, c’est qu’il n’y a toujours pas de doc.

Donc non, l’informatique n’est pas plus facile aujourd’hui. Il y a plus à savoir. Ça change plus vite. Chacun est plus cloisonné dans sa bulle de connaissance spécialisée. Et ça s’accélère.

Les challenges sont là, juste différents, mais la demande est immensément plus forte.

Et puis vous imaginez la gueule de l’offre d’emploi pour recruter ce profil ? Doit parler anglais, 7 ans d’expérience en mécanique quantique, taper en Bépo est un plus. On paie le SMIC mais on offre le café illimité comme chez Google.

A cela se rajoute le problème que les formations ne suivent pas.

Elles ne produisent pas assez d’informaticiens.

Elles produisent des profils sur des technos qui ne sont pas à jour, qui ne correspondent pas à la demande du marché.

Et surtout, elles produisent des nazes.

Pardonnez-moi, jeunes gens, ce n’est pas personnel.

Mais 90% des gens qui sortent de l’école, je ne souhaite jamais bosser avec. Jamais.

Ils sont mauvais, au point de ne pas savoir coder un script simple. Certains ne savent pas exprimer une idée clairement, et encore moins définir un problème. Même pas poser les bonnes questions.

Alors oui, ça peut s’améliorer une fois en entreprise, mais qui a le temps ? Qui a l’envie ? Qui a l’argent ?

Vous vous imaginez en train d’embaucher un cuisinier qui ne sait pas faire cuir un oeuf ?

C’est exactement ce qui se passe en informatique.

D’un côté on a des demandes du marché pour des profils qui font plus.

De l’autre on a des filières qui mettent sur le marché des gens qui ne font rien.

En même temps, on n’est pas près à payer ceux qui ont les compétences au juste prix, et les grosses boîtes comme Google, Facebook, Microsoft, Yahoo, Instragram, Twitter, etc. raflent tout.

Il ne reste plus rien.

Je résume :

Voilà la situation aujourd’hui.

Et j’entends encore des devs qui me disent qu’ils ne trouvent pas du boulot.

Et ça m’énerve !

Il y a d’abord le mec, qui ne veut pas bouger, pas changer de technos, pas se mettre à jour, et cherche une fois par mois de la même façon que le faisait sa grand-mère.

Il y a la meuf qui est dans le fond de la creuse sur un modem 56k et qui ne comprend pas que les starts up ne frappent pas à sa porte.

Ceux qui ont 3 enfants et qui ne peuvent pas. Peuvent pas quoi, je ne sais pas, mais ils peuvent pas. Ceux qui envoient des CV et n’appellent jamais. Ceux qui arrivent à l’entretien d’embauche avec des miettes dans la barbe. Ceux qui attendent chez eux qu’un miracle arrive alors qu’ils ont 15 évènements de réseautage dans leur inbox…

Bref, non seulement le marché est déséquilibré, mais une partie du vivier s’assure activement de rester inaccessible à l’embauche.

En plus — merde ! — le dev c’est quand même un des métiers les plus permissifs du monde.

Tu es en chaise roulante ? Cool des aides.

Tu as des piercings ? Ranafout.

Tu as la capacité sociale d’une moule ? On s’arrange.

Tu veux bosser chez toi ? Ça se négocie.

Alors je ne dis pas que tout le monde embauche. Je ne prétends pas qu’il suffit de se balader avec une pancarte dans la rue avec marqué « échange COBOL contre soussous » pour faire fortune.

Mais tout de même, on est sur le marché le plus florissant du monde. Faites péter le champagne !

Et si vous êtes recruteurs, préparez-vous à devenir attractif. Car vous risquez fort de vous retrouver uniquement avec le fond du panier, et à remercier le ciel qu’on vous en ait laissé.

Or la compétitivité d’une boite dépend aujourd’hui tout autant de sa vitrine IRL que de celle en ligne. Et le prix du ticket d’entrée du service minimum a pris une sacrée inflation. J’ai vu cette semaine une meuf s’enerver qu’un site ne marchait pas parce que la barre de recherche n’avait pas de résultat live : il fallait appuyer sur le bouton pour avoir les résultats.

Tirez-en la conclusion que vous voulez, mais tirez-la vite.

Error happened! 0 - count(): Argument #1 ($value) must be of type Countable|array, null given In: /var/www/ecirtam.net/autoblogs/autoblogs/autoblog.php:428 http://ecirtam.net/autoblogs/autoblogs/sametmaxcom_a844ada43a979e3b1395ab9acb6afafb84340999/?56 #0 /var/www/ecirtam.net/autoblogs/autoblogs/autoblog.php(999): VroumVroum_Blog->update() #1 /var/www/ecirtam.net/autoblogs/autoblogs/sametmaxcom_a844ada43a979e3b1395ab9acb6afafb84340999/index.php(1): require_once('...') #2 {main}