App-Sqitch
view release on metacpan or search on metacpan
lib/sqitchtutorial.pod view on Meta::CPAN
> cat sqitch.plan
%syntax-version=1.0.0
%project=flipr
%uri=https://github.com/sqitchers/sqitch-intro/
appschema 2013-12-30T23:19:45Z Marge N. OâVera <marge@example.com> # Add schema for all flipr objects.
users [appschema] 2013-12-30T23:49:00Z Marge N. OâVera <marge@example.com> # Creates table to track our users.
insert_user [users appschema] 2013-12-30T23:57:36Z Marge N. OâVera <marge@example.com> # Creates a function to insert a user.
change_pass [users appschema] 2013-12-30T23:57:45Z Marge N. OâVera <marge@example.com> # Creates a function to change a user password.
@v1.0.0-dev1 2013-12-31T00:01:22Z Marge N. OâVera <marge@example.com> # Tag v1.0.0-dev1.
lists [appschema users] 2013-12-31T00:39:40Z Marge N. OâVera <marge@example.com> # Adds table for storing lists.
insert_list [lists appschema users] 2013-12-31T00:41:29Z Marge N. OâVera <marge@example.com> # Creates a function to insert a list.
delete_list [lists appschema users] 2013-12-31T00:41:37Z Marge N. OâVera <marge@example.com> # Creates a function to delete a list.
flips [appschema users] 2013-12-31T00:32:39Z Marge N. OâVera <marge@example.com> # Adds table for storing flips.
insert_flip [flips appschema users] 2013-12-31T00:35:59Z Marge N. OâVera <marge@example.com> # Creates a function to insert a flip.
delete_flip [flips appschema users] 2013-12-31T00:36:34Z Marge N. OâVera <marge@example.com> # Creates a function to delete a flip.
Much much better, a nice clean main now. And because it is now identical to
the "flips" branch, we can just carry on. Go ahead and tag it, bundle, and
release:
> sqitch tag v1.0.0-dev2 -n 'Tag v1.0.0-dev2.'
Tagged "delete_flip" with @v1.0.0-dev2
> git commit -am 'Tag the database with v1.0.0-dev2.'
[main 230603b] Tag the database with v1.0.0-dev2.
1 file changed, 1 insertion(+)
> git tag v1.0.0-dev2 -am 'Tag v1.0.0-dev2'
> sqitch bundle --dest-dir flipr-1.0.0-dev2
Bundling into flipr-1.0.0-dev2
Writing config
Writing plan
Writing scripts
+ appschema
+ users
+ insert_user
+ change_pass @v1.0.0-dev1
+ lists
+ insert_list
+ delete_list
+ flips
+ insert_flip
+ delete_flip @v1.0.0-dev2
Note the use of the C<--dest-dir> option to C<sqitch bundle>. Just a nicer way
to create the top-level directory name so we don't have to rename it from
F<bundle>.
=head1 In Place Changes
Uh-oh, someone just noticed that MD5 hashing is not particularly secure. Why?
Have a look at this:
> psql -d flipr_test -c "
SELECT flipr.insert_user('foo', 'secr3t'), flipr.insert_user('bar', 'secr3t');
SELECT * FROM flipr.users;
"
nickname | password | timestamp
----------+----------------------------------+-------------------------------
foo | 9695da4dd567a19f9b92065f240c6725 | 2013-12-31 00:56:20.240481+00
bar | 9695da4dd567a19f9b92065f240c6725 | 2013-12-31 00:56:20.240481+00
If user "foo" ever got access to the database, she could quickly discover that
user "bar" has the same password and thus be able to exploit the account. Not
a great idea. So we need to modify the C<insert_user()> and C<change_pass()>
functions to fix that. How?
We'll use
L<C<pgcrypto>|https://www.postgresql.org/docs/current/static/pgcrypto.html>'s
C<crypt()> function to encrypt passwords with a salt, so that they're all
unique. We just add a change to add C<pgcrypto> to the database, and then we
can use it. The deploy script should be:
CREATE EXTENSION pgcrypto;
And the revert script should be:
DROP EXTENSION pgcrypto;
=over
If you're on PostgreSQL 9.0 or lower, you won't be able to deploy C<pgcrypto>
with a Sqitch change, alas. You'll have to install it manually, like so:
psql -d flipr_test -f /path/to/pgsql/share/contrib/pgcrypto.sql
Don't forget to do this with your staging and production databases, too. Or
consider upgrading to PostgreSQL 9.1 or higher; the SQL-level extension
support is amazingly useful.
=back
We're going to use the C<crypt()> and C<gen_salt()> functions, so in the
C<verify> script, let's make sure that the extension exists I<and> that both
those functions exist:
SELECT 1/count(*) FROM pg_extension WHERE extname = 'pgcrypto';
SELECT has_function_privilege('crypt(text, text)', 'execute');
SELECT has_function_privilege('gen_salt(text)', 'execute');
Now we can use C<pgcrypto>. But how to deploy the changes to C<insert_user()>
and C<change_pass()>?
Normally, modifying functions in database changes is a
L<PITA|https://www.urbandictionary.com/define.php?term=pita>. You have to make
changes like these:
=over
=item 1.
Copy F<deploy/insert_user.sql> to F<deploy/insert_user_crypt.sql>.
=item 2.
Edit F<deploy/insert_user_crypt.sql> to switch from C<MD5()> to C<crypt()>
and to add a dependency on the C<pgcrypto> change.
=item 3.
Copy F<deploy/insert_user.sql> to F<revert/insert_user_crypt.sql>.
( run in 1.099 second using v1.01-cache-2.11-cpan-39bf76dae61 )